Я имею в использовании ВИМ (арг и argdo) всякий раз , когда мне нужно «подтверждение», но было интересно , если там был «простой» способ
Yuvi
1
Это идет вразрез с основной целью sed - автоматизировать редактирование над потоком.
teppic
@teppic не совсем, потому что вам все равно придется искать экземпляры в текстовых файлах, что может сделать для вас sed. Я думаю, что вопрос имеет смысл, на тот случай, если вы добавили неправильные файлы в список и хотели посмотреть, какой файл вы редактировали
Колоб Каньон,
Ответы:
37
Делать это с 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добавляя в них имена путей:
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будут разбиты на слова в пробелах, и эти слова будут подвергнуты глобализации имени файла (это дисквалифицирует пути, содержащие пробелы и специальные символы).
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- то в дополнение к вышесказанному он также просит заменить первую строку на " линия "для каждой строки.
Ответы:
Делать это с
sed
, вероятно, было бы невозможно, поскольку это неинтерактивный редактор потоков. Завершениеsed
в сценарии потребовало бы слишком много размышлений. Проще сделать это с помощьюvim
:Поскольку это было упомянуто в комментариях ниже, вот как это будет использоваться для нескольких файлов, соответствующих определенному шаблону выделения имени файла в текущем каталоге:
Или, если вы сначала хотите убедиться, что файл действительно содержит строку, которая соответствует заданному шаблону, прежде чем выполнять замену,
Вышеупомянутые два
find
цикла оболочки, модифицированные в команды, которые делают то же самое, но для всех файлов с определенным именем где-то в или в некоторомtop-dir
каталоге,Или, используя оригинальные циклы оболочки и
find
добавляя в них имена путей:Вы, в любом случае, не хотите сделать что - то вроде
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
Вы можете получить это, сделав так:
В частности, добавление
c
после третьего разделителя.Обратите внимание, что опция 'c' работает только в Vim; вы не сможете использовать его
sed
в командной строке.источник
sed
.vim
, поэтому этот ответ применим; хотя явно у vim и sed разные способностиВы можете разрешить
sed
делать свою работу с файлом и затем сохранить результат во временном файле, который затем можно интерактивно вставить в исходный файл, используяsdiff
(см. Http://www.gnu.org/software/diffutils/manual/diffutils.html. # Invoking-sdiff ):источник
Если вы передаете это с одним аргументом -
searchandreplace "AAA"
он ищет только эту строку в текущем каталоге, но если вы передаете его с двойными аргументамиsearchandreplace AAA BBB
- то в дополнение к вышесказанному он также просит заменить первую строку на " линия "для каждой строки.источник