Подтвердить что ты не робот

Sed beginner: изменение всех вхождений в папке

Мне нужно найти и заменить регулярное выражение во всех файлах в папке (и ее подпапках). Какая будет команда оболочки linux для этого?

Например, я хочу запустить это по всем файлам и перезаписать старый файл с новым, замененным текстом.

sed 's/old text/new text/g' 
4b9b3361

Ответ 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