Есть ли способ заставить sed спрашивать у меня подтверждение перед каждой заменой? Нечто похожее на 'c' при использовании замены внутри vim.
Сед делает это вообще?
Есть ли способ заставить sed спрашивать у меня подтверждение перед каждой заменой? Нечто похожее на 'c' при использовании замены внутри vim.
Сед делает это вообще?
Ответы:
Делать это с sed
, вероятно, было бы невозможно, поскольку это неинтерактивный редактор потоков. Завершение sed
в сценарии потребовало бы слишком много размышлений. Проще сделать это с помощью vim
:
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' file.in
Поскольку это было упомянуто в комментариях ниже, вот как это будет использоваться для нескольких файлов, соответствующих определенному шаблону выделения имени файла в текущем каталоге:
for fname in file*.txt; do
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Или, если вы сначала хотите убедиться, что файл действительно содержит строку, которая соответствует заданному шаблону, прежде чем выполнять замену,
for fname in file*.txt; do
grep -q 'PATTERN' "$fname" &&
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Вышеупомянутые два find
цикла оболочки, модифицированные в команды, которые делают то же самое, но для всех файлов с определенным именем где-то в или в некотором top-dir
каталоге,
find top-dir -type f -name 'file*.txt' \
-exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
find top-dir -type f -name 'file*.txt' \
-exec grep -q 'PATTERN' {} \; \
-exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
Или, используя оригинальные циклы оболочки и find
добавляя в них имена путей:
find top-dir -type f -name 'file*.txt' -exec sh -c '
for pathname do
vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
done' sh {} +
find top-dir -type f -name 'file*.txt' -exec sh -c '
for pathname do
grep -q "PATTERN" "$pathname" &&
vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
done' sh {} +
Вы, в любом случае, не хотите сделать что - то вроде for filename in $( grep -rl ... )
так
grep
работу еще до начала первой итерации цикла, которая не является элегантной , иgrep
будут разбиты на слова в пробелах, и эти слова будут подвергнуты глобализации имени файла (это дисквалифицирует пути, содержащие пробелы и специальные символы).Связанный:
sed
том, что он может работать с несколькими файлами, например, sed -i 's/old/new/g' /path/to/*.txt
или с чем-то похожим.
for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
Вы можете получить это, сделав так:
:%s/OLD_TEXT/NEW_TEXT/gc
В частности, добавление c
после третьего разделителя.
Обратите внимание, что опция 'c' работает только в Vim; вы не сможете использовать его sed
в командной строке.
sed
.
vim
, поэтому этот ответ применим; хотя явно у vim и sed разные способности
Вы можете разрешить sed
делать свою работу с файлом и затем сохранить результат во временном файле, который затем можно интерактивно вставить в исходный файл, используя sdiff
(см. Http://www.gnu.org/software/diffutils/manual/diffutils.html. # Invoking-sdiff ):
sed -r 's/something/something_else/g' my_file > tmp_file
sdiff -o my_file -s -d my_file tmp_file
searchandreplace () {
if [ -z $2 ] ; then
realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
else
realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
exp=$(realpath * | xargs grep -ins --directories=skip --color=never "$1" | cut -d':' -f1,2 | awk -F':' '{print $2 $1}' | sed -E "s|^[0-9]+|sed -i \'&s/|; s|//|/"$1"/"$2"/g\' /|")
IFS=$'\n'
for d in $exp
do
read -p "Exec $(echo -e -n "\033[1;31m$d\033[0m")? " -e REP
if [ "$REP" = y ]; then
echo `bash -c $d`;
fi
done
fi
}
Если вы передаете это с одним аргументом - searchandreplace "AAA"
он ищет только эту строку в текущем каталоге, но если вы передаете его с двойными аргументами searchandreplace AAA BBB
- то в дополнение к вышесказанному он также просит заменить первую строку на " линия "для каждой строки.