sed новичок: изменение всех вхождений в папке - PullRequest
73 голосов
/ 25 мая 2009

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

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

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

Ответы [ 6 ]

108 голосов
/ 25 мая 2009

Нет способа сделать это, используя только sed. Вам нужно будет использовать хотя бы утилиту поиска вместе:

find . -type f -exec sed -i.bak "s/foo/bar/g" {} \;

Эта команда создаст файл .bak для каждого измененного файла.

Примечания:

  • Аргумент -i для команды sed является расширением GNU, поэтому, если вы запускаете эту команду с sed BSD, вам нужно перенаправить вывод в новый файл, а затем переименовать его.
  • Утилита find не реализует аргумент -exec в старых блоках UNIX, поэтому вам нужно будет использовать | xargs.
35 голосов
/ 21 января 2015

Я предпочитаю использовать find | xargs cmd вместо find -exec, потому что его легче запомнить.

Этот пример глобально заменяет «foo» на «bar» в файлах .txt в вашем текущем каталоге или ниже:

find . -type f -name "*.txt" -print0 | xargs -0 sed -i "s/foo/bar/g"

Опции -print0 и -0 могут быть пропущены, если ваши имена файлов не содержат прикольных символов, таких как пробелы.

6 голосов
/ 25 мая 2009

Для переносимости я не полагаюсь на особенности sed, специфичные для linux или BSD. Вместо этого я использую сценарий overwrite из книги Кернигана и Пайка о среде программирования Unix.

Команда тогда будет

find /the/folder -type f -exec overwrite '{}' sed 's/old/new/g' {} ';'

А скрипт overwrite (который я использую повсюду) -

#!/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 "$@" >$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 сможет его прочитать.

1 голос
/ 25 мая 2009

Могу ли я предложить (после резервного копирования ваших файлов):

find /the/folder -type f -exec sed -ibak 's/old/new/g' {} ';'
0 голосов
/ 21 августа 2016

Если имена файлов в папке имеют обычные имена (например, file1, file2 ...), которые я использовал для цикла.

for i in {1..10000..100}; do sed 'old\new\g' 'file'$i.xml > 'cfile'$i.xml; done
0 голосов
/ 25 мая 2009

Возможно, стоит попробовать мой массовый поиск / замена Perl-скрипта . Имеет некоторые преимущества по сравнению с решениями с цепочечной полезностью (например, нет необходимости иметь дело с несколькими уровнями интерпретации метасимволов оболочки).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...