Sed beginner: изменение всех вхождений в папке
Мне нужно найти и заменить регулярное выражение во всех файлах в папке (и ее подпапках). Какая будет команда оболочки linux для этого?
Например, я хочу запустить это по всем файлам и перезаписать старый файл с новым, замененным текстом.
sed 's/old text/new text/g'
Ответы
Ответ 1
Нет способа сделать это, используя только sed. Вам нужно будет использовать хотя бы утилиту find:
find . -type f -exec sed -i.bak "s/foo/bar/g" {} \;
Эта команда создаст файл .bak
для каждого измененного файла.
Примечания:
- Аргумент
-i
для команды sed
- это расширение GNU, поэтому, если вы используете эту команду с BSD sed
, вам нужно будет перенаправить вывод в новый файл, а затем переименуйте его.
- Утилита
find
не использует аргумент -exec
в старых блоках UNIX, поэтому вам нужно будет использовать | xargs
.
Ответ 2
Я предпочитаю использовать find | xargs cmd
над find -exec
, потому что его легче запомнить.
В этом примере глобально заменяется "foo" на "bar" в .txt файлах в вашем текущем каталоге или ниже:
find . -type f -name "*.txt" -print0 | xargs -0 sed -i "s/foo/bar/g"
Параметры -print0
и -0
могут быть опущены, если ваши имена файлов не содержат фанковых символов, таких как пробелы.
Ответ 3
Для переносимости я не полагаюсь на особенности sed, специфичные для Linux или BSD. Вместо этого я использую overwrite
script из книги Kernighan и Pike в среде программирования Unix.
Затем команда
find /the/folder -type f -exec overwrite '{}' sed 's/old/new/g' {} ';'
И overwrite
script (который я использую повсюду)
#!/bin/sh
# overwrite: copy standard input to output after EOF
# (final version)
# set -x
case $# in
0|1) echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2
esac
file=$1; shift
new=/tmp/$$.new; old=/tmp/$$.old
trap 'rm -f $new; exit 1' 1 2 15 # clean up files
if "[email protected]" >$new # collect input
then
cp $file $old # save original file
trap 'trap "" 1 2 15; cp $old $file # ignore signals
rm -f $new $old; exit 1' 1 2 15 # during restore
cp $new $file
else
echo "overwrite: $1 failed, $file unchanged" 1>&2
exit 1
fi
rm -f $new $old
Идея состоит в том, что она перезаписывает файл только в том случае, если команда выполнена успешно. Полезно в find
, а также где вы не захотите использовать
sed 's/old/new/g' file > file # THIS CODE DOES NOT WORK
потому что оболочка обрезает файл до того, как sed
может его прочитать.
Ответ 4
Могу ли я предложить (после резервного копирования ваших файлов):
find /the/folder -type f -exec sed -ibak 's/old/new/g' {} ';'
Ответ 5
Возможно, вы захотите попробовать мой массовый поиск/замена Perl script. Имеет некоторые преимущества по сравнению с решениями с цепочкой (например, не нужно иметь дело с несколькими уровнями интерпретации метасимволов оболочки).
Ответ 6
Если имя файла в папке имеет некоторые обычные имена (например, file1, file2...), я использовал для цикла.
for i in {1..10000..100}; do sed 'old\new\g' 'file'$i.xml > 'cfile'$i.xml; done