Как выполнить подстановку sed на месте, которая создает только резервные копии файлов, которые были изменены?


13

Я запустил следующее, чтобы заменить термин, используемый во всех файлах в текущем рабочем каталоге:

$ find . -type f -print0 | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

Это выполняло подстановку слова, но также создавало .bupфайлы файлов, которые никогда не имели Ms. Johnsonстроки.

Как выполнить замену, не создавая все эти ненужные резервные копии?


мне кажется как баг
— сэд

Вероятно, есть лучший подход, возможный с использованием exи условно (только если файл изменен), выполняемый :!cp '%' '%.bup'перед сохранением и выходом. Может быть стоит посмотреть.
— Wildcard

Я написал вопрос о моей идее выше на viстеке обмена.
— Wildcard

Ответы:


6

Вы можете проверить содержимое файлов, чтобы убедиться, что подстановка будет иметь место при работе sedс ними:

find . \
    -type f \
    -exec grep -q 'Ms. Johnson' {} \; \
    -print0 |
xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

Если вы хотите быть действительно умным, вы можете findвообще отказаться от использования :

grep -Z -l -r 'Ms. Johnson' |
    xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

1
Я думаю, тебе нужно как '{}'раз перед тем, как ты \;в этом -exec.
— Jander

8

В Find есть -execоператор, который выполняет произвольную команду. Более того, -execэто тест , так что вы можете -execобъединить несколько s вместе, и если более ранние команды не пройдут, более поздние не будут выполнены. Строка {}заменяется текущим именем файла и ;отмечает конец команды. Вы должны процитировать оба, чтобы избежать вмешательства оболочки.

Так:

find . -type f \
    -exec grep -q 'Ms. Johnson' '{}' \; \
    -exec sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g' '{}' \;

У меня никогда не было проблем с использованием голых {}.
— амфетамина

1
@amphetamachine: Я тоже, но страница руководства предлагает это. Это может быть что-то вроде csh, или могут быть оболочки (не Bash и не POSIX), которые раскрываются {}в пустую строку при выполнении фигурных скобок.
— Декабрь

4

Я посмотрел на справочную страницу и не нашел способа сделать это напрямую sed, как я уверен, что вы сделали, прежде чем спрашивать. Я вижу несколько способов обойти это с помощью grep, но я думаю, что самый простой это:

grep -rlZ "Ms. Johnson" . | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

-rrecurse
-lprint filename только
-Zконечные имена с нулем


-1

Похоже, вам нужно сначала создать список файлов, которые соответствуют вашим условиям поиска.

search="test"
for match in $(find -type f -exec grep -l $search "{}" \;)
do sed -i'.bup' -e "/$search/ s/$search/Mrs. Melbin/g" "$match"
done

Вы забыли .как первый аргумент find. Кроме того, как мне сообщили не так давно, на самом деле вам не нужно цитировать или избегать{}
— Кевин

Не генерируйте список файлов и не выполняйте подстановку команд. Сначала findгенерируется список файлов, разделенных новой строкой, затем оболочка разбивает этот список на любые пробелы (не только на новые строки), а затем оболочка обрабатывает каждое слово как шаблон глобуса. Это работает, только если ваши имена файлов не содержат пробелов или \[?*. Другие ответы на этой странице показывают, как это сделать правильно.
— Жиль "ТАК - перестань быть злым"

@Kevin В .find нет необходимости (по крайней мере, find найдено в linux), потому что он предполагается, когда аргумент не передан пути.
— laebshade
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.