Как выполнить рекурсивный поиск / замену строки с помощью awk или sed?

avatar
Tedd
17 октября 2009 в 21:10
608194
35
777

Как найти и заменить каждое вхождение:

subdomainA.example.com

с

subdomainB.example.com

в каждом текстовом файле в дереве каталогов /home/www/ рекурсивно?

Источник
J. Polfer
8 ноября 2010 в 19:42
99

Совет: не делайте нижеприведенное в дереве проверки svn ... это перезапишет файлы волшебной папки .svn.

J. Katzwinkel
6 февраля 2013 в 17:56
8

Боже мой, это именно то, что я только что сделал. Но это сработало и, похоже, не причинило никакого вреда. Что худшего могло случиться?

ninjagecko
14 мая 2013 в 13:36
5

@ J.Katzwinkel: по крайней мере, это может повредить контрольные суммы, что может повредить ваш репозиторий.

funroll
3 октября 2014 в 19:09
3

Совет для всех, кто использует sed: он добавит завершающие символы новой строки в ваши файлы. Если они вам не нужны, сначала выполните поиск-замену, которая ничего не найдет, и зафиксируйте это в git. Тогда сделай настоящий. Затем интерактивно переустановите и удалите первый.

tripleee
19 февраля 2016 в 05:44
0

@funroll Или используйте инструмент, который не требует принудительного добавления новой строки. например Perl; или принять тот факт, что POSIX строго требует, чтобы текстовые файлы имели окончания строк.

devinbost
24 августа 2016 в 19:58
6

Вы можете исключить каталог, например git, из результатов, используя -path ./.git -prune -o в find . -path ./.git -prune -o -type f -name '*matchThisText*' -print0 перед подключением к xargs

Sylhare
24 мая 2019 в 14:27
0

Этот ответ на веб-сайте Unix StackExchange тоже довольно хорош: unix.stackexchange.com/a/112024/354626

ashleedawg
2 августа 2020 в 13:55
0

Альтернативное решение от SuperUser Как я могу выполнить рекурсивный поиск и замену из командной строки?: find . -type f \( -iname \*.ht* -o -iname \*.php \) -exec sed -i'' -e 's/findString/replString/g' {} + (строки должны быть экранированы, например, точки типа \.) Могут игнорироваться имена файлов с пробелами (?)

Ответы (35)

avatar
microo8
25 мая 2020 в 10:06
6

или используйте невероятно быстрый параллельный GNU:

grep -rl oldtext . | parallel sed -i 's/oldtext/newtext/g' {}
eri0o
26 мая 2020 в 18:17
0

как установить GNU Parallel?

microo8
27 мая 2020 в 06:12
0

попробуйте найти параллельный пакет. арка: sudo pacman -S parallel; ubuntu / debian: sudo apt-get install parallel; шляпа-шляпа: dnf install parallel; Я использую арку кстати

avatar
Sazzad Hissain Khan
9 октября 2019 в 03:27
11

Самый простой способ заменить ( все файлы, каталог, рекурсивный )

find . -type f -not -path '*/\.*' -exec sed -i 's/foo/bar/g' {} +

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

Если вы хотите включить скрытые файлы, используйте

find . -type f  -exec sed -i 's/foo/bar/g' {} +

В обоих случаях строка foo будет заменена новой строкой bar

avatar
inetphantom
31 октября 2018 в 08:43
11

Простой метод, если вам нужно исключить каталоги (--exclude-dir=..folder), а также могут иметь имена файлов с пробелами (решено с использованием 0Byte для 41 <2800> и xargs -0>)

grep -rlZ oldtext . --exclude-dir=.folder | xargs -0 sed -i 's/oldtext/newtext/g'
avatar
bbarker
25 сентября 2018 в 21:33
2

Вот версия, которая должна быть более общей, чем большинство других; например, для него не требуется find (вместо него используется du). Для этого действительно требуется xargs, который есть только в некоторых версиях Plan 9 (например, 9front).

 du -a | awk -F' '  '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'

Если вы хотите добавить фильтры, такие как расширения файлов, используйте grep:

 du -a | grep "\.scala$" | awk -F' '  '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
avatar
tgunr
21 февраля 2018 в 21:37
2

Я просто использую топы:

find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 |  xargs -0 tops -verbose  replace "verify_noerr(<b args>)" with "__Verify_noErr(<args>)" \
replace "check(<b args>)" with "__Check(<args>)" 
FractalSpace
10 апреля 2018 в 19:35
0

плюс один для `'*. [c | cc | cp | cpp | m | mm | h]'`

avatar
J.Hpour
3 февраля 2018 в 10:06
4

Согласно этому сообщению в блоге:

find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'
Pathros
16 марта 2018 в 20:09
0

Как избежать косой черты /?. Например, я хочу заменить IP-адреса: xxx.xxx.xxx.xxx на xxx.xxx.xxx.xxx/folder

J.Hpour
17 марта 2018 в 15:55
0

Вы можете избежать / с помощью \. Например: find . -type f | xargs perl -pi -e 's/xxx.xxx.xxx.xxx\/folder/newtext/g;'

avatar
domdambrogia
22 августа 2017 в 20:28
17

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

grep -rl <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g

Если вы запустите man grep, вы заметите, что вы также можете определить флаг --exlude-dir="*.git", если хотите опустить поиск в каталогах .git, избегая проблем с индексом git, как вежливо указали другие.

Направляет вас на:

grep -rl --exclude-dir="*.git" <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
avatar
Sheena
20 июля 2017 в 11:57
1
perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *`
pevik
24 января 2018 в 15:59
1

Не используется awk / sed, но часто используется perl (кроме встроенных / только систем с busybox).

avatar
NeronLeVelu
31 марта 2017 в 11:54
2

просто чтобы не менять также

  • Почти поддоменA.example.com
  • subdomainA.example.comp.other

, но все же

  • subdomainA.example.com.IsIt.good

(возможно, не очень подходит идея корневого домена)

find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \;
avatar
Perseids
31 марта 2017 в 09:47
1

Для замены всех вхождений в репозитории git вы можете использовать:

git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'

См. Список файлов в локальном репозитории git?, чтобы узнать о других параметрах для вывода списка всех файлов в репозитории. Параметры -z указывают git разделять имена файлов нулевым байтом, что гарантирует, что xargs (с параметром -0) может разделять имена файлов, даже если они содержат пробелы или еще много чего.

avatar
mathiasrw
17 марта 2017 в 13:40
0

Если у вас есть доступ к узлу, вы можете сделать npm install -g rexreplace, а затем

rexreplace 'subdomainA.example.com' 'subdomainB.example.com' /home/www/**/*.*
avatar
Klas. S
22 января 2017 в 13:22
0

Чтобы заменить все содержимое, соответствующее string_1 на string_2 всех .c и и <6806149842280> в текущем каталоге и <6806149842280> вложенных файлах. > (кроме .git /) .

Это работает на Mac :

find . -type f -path "*.git*" -prune -o -name '*\.[ch]' -exec \
sed -i '' -e 's/'$1'/'$2'/g' {} +

Это должно работать на Linux (еще не тестировал):

find . -type f -path "*.git*" -prune -o -name '*\.[ch]' -exec \
sed -i 's/string_1/string_2/g' {} +
avatar
Raphvanns
21 ноября 2016 в 19:41
2

Немного старой школы, но это работало на OS X.

Есть несколько уловок:

• Будет редактировать только файлы с расширением .sls в текущем каталоге

. должен быть экранирован, чтобы гарантировать, что sed не оценивает их как «любой символ»

, используется в качестве разделителя sed вместо обычного /

Также обратите внимание, что это необходимо для редактирования шаблона Jinja для передачи variable в пути к import (но это не по теме).

Сначала убедитесь, что ваша команда sed выполняет то, что вы хотите (это будет печатать только изменения в stdout, файлы не изменятся):

for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done

При необходимости отредактируйте команду sed, когда будете готовы внести изменения:

for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed -i '' 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done

Обратите внимание на -i '' в команде sed , я не хотел создавать резервную копию исходных файлов (как описано в Редактирование на месте с помощью sed в OS X или в комментарии Роберта Луджо на этой странице).

С праздником, народ!

avatar
Jacob Wang
2 сентября 2016 в 05:19
32

Для всех, кто использует поисковик серебра (ag)

ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'

Поскольку по умолчанию ag игнорирует файлы / папки git / hg / svn, его можно безопасно запускать внутри репозитория.

reducing activity
22 марта 2021 в 15:53
0

Спасибо за рабочее решение! Мне нужно будет найти эквивалент с помощью ripgrep.

Jacob Wang
22 марта 2021 в 16:00
0

@reductivity Проверьте github.com/chmln/sd :) Я счастливый пользователь

mnme
6 июля 2021 в 14:44
0

Замена ag на rg для ripgrep тоже отлично работает.

avatar
sarath kumar
4 июля 2016 в 11:53
5

Вы можете использовать awk для решения этой проблемы, как показано ниже:

for file in `find /home/www -type f`
do
   awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file;
done

надеюсь, это поможет вам !!!

Jankapunkt
13 марта 2018 в 15:13
0

Работает на MacO без проблем! Все команды на основе sed завершились ошибкой, когда двоичные файлы были включены, даже с конкретными настройками osx.

Soren Bjornstad
15 февраля 2019 в 20:53
0

Осторожно ... это взорвется, если какой-либо из возвращаемых файлов find будет содержать пробел в своем имени! Намного безопаснее использовать while read: coderhelper.com/a/9612560/1938956

avatar
seddonym
24 июня 2016 в 08:26
15

Этот совместим с репозиториями git и немного проще:

Linux:

git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'

Mac:

git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g'

(Спасибо http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/)

gniourf_gniourf
24 июня 2016 в 08:42
0

Разумнее использовать параметр git-grep -z вместе с xargs -0.

tripleee
24 июня 2016 в 08:59
0

git grep очевидно имеет смысл только в репо git. Общая замена - grep -r.

Petr Peller
24 января 2017 в 10:56
0

@gniourf_gniourf Вы можете объяснить?

gniourf_gniourf
24 января 2017 в 12:25
2

@PetrPeller: с -z, git-grep будет разделять поля вывода нулевыми байтами вместо символов новой строки; а с -0, xargs будет читать ввод, разделенный нулевыми байтами, вместо пробелов (и не делать странных вещей с кавычками). Поэтому, если вы не хотите, чтобы команда прерывалась, если имена файлов содержат пробелы, кавычки или другие забавные символы, используйте следующую команду: git grep -z -l 'original_text' | xargs -0 sed ....

avatar
cchamberlain
25 июля 2015 в 20:44
0

Это лучшее универсальное решение, которое я нашел для OSX и Windows (msys2). Должен работать со всем, что может получить версию sed для gnu. Пропускает каталоги .git, чтобы не повредить ваши контрольные суммы.

На Mac просто сначала установите coreutils и убедитесь, что gsed находится в пути -

brew install coreutils

Затем я вставляю эту функцию в свой zshrc / bashrc ->

replace-recursive() {
    hash gsed 2>/dev/null && local SED_CMD="gsed" || SED_CMD="sed"
    find . -type f -name "*.*" -not -path "*/.git/*" -print0 | xargs -0 $SED_CMD -i "s/$1/$2/g"
}

usage: replace-recursive <find> <replace>
avatar
MadMan2064
29 мая 2015 в 05:34
5

grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done

Думаю, большинство людей не знают, что они могут передать что-то в "файл во время чтения", и это позволяет избежать этих неприятных аргументов -print0, сохраняя при этом пробелы в именах файлов.

Дальнейшее добавление echo перед sed позволяет вам увидеть, какие файлы будут изменены, прежде чем это делать.

tripleee
18 февраля 2016 в 06:30
0

Причина, по которой -print0 полезен, заключается в том, что он обрабатывает случаи, которые while read просто не может обработать - новая строка является допустимым символом в имени файла Unix, поэтому для того, чтобы ваш код был полностью надежным, он должен справляться с такими именами файлов , слишком. (Кроме того, вы хотите read -r, чтобы избежать неприятного поведения устаревшего POSIX в read.)

tripleee
18 февраля 2016 в 06:31
0

Кроме того, sed не работает, если нет совпадений, поэтому grep на самом деле не требуется; хотя это полезная оптимизация, позволяющая избежать перезаписи файлов, которые не содержат совпадений, если у вас их много, или если вы хотите избежать ненужного обновления меток даты в файлах.

avatar
mzcl-mn
2 марта 2015 в 11:32
3

Если вы не против использования vim вместе с инструментами grep или find, вы можете проследить ответ пользователя Герта по этой ссылке -> Как выполнить замену текста в большая иерархия папок?.

Вот сделка:

  • рекурсивно grep для строки, которую вы хотите заменить в определенном пути, и взять только полный путь соответствующего файла. (это будет $(grep 'string' 'pathname' -Rl) .

  • (необязательно), если вы хотите сделать предварительную резервную копию этих файлов в централизованном каталоге, возможно, вы также можете использовать это: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'

  • после этого вы можете редактировать / заменять по желанию в vim, следуя схеме, аналогичной той, которая представлена ​​по указанной ссылке:

    • :bufdo %s#string#replacement#gc | update
avatar
Pawel
15 января 2015 в 11:38
1

Использование комбинации grep и sed

for pp in $(grep -Rl looking_for_string)
do
    sed -i 's/looking_for_string/something_other/g' "${pp}"
done
Pawel
18 февраля 2016 в 22:04
0

@tripleee Я немного изменил это. В этом случае вывод для команды grep -Rl pattern сгенерировал список файлов, в которых находится шаблон. Файлы не читаются в цикле for.

tripleee
19 февраля 2016 в 05:45
0

Хм? У вас все еще есть цикл for; если какое-либо возвращенное имя файла содержит пробелы, оно не будет работать правильно, поскольку оболочка токенизирует список аргументов for. Но тогда вы используете переменную имени файла без кавычек внутри цикла, поэтому, если вы исправите это, она сломается там. Исправление этих оставшихся ошибок сделало бы ваш ответ идентичным ответу @ MadMan2064.

Pawel
19 февраля 2016 в 17:03
0

@tripleee да, это правда, я это пропустил.

avatar
Marcus Floyd
30 октября 2014 в 04:18
1

Если вы хотите использовать это без полного разрушения репозитория SVN, вы можете указать find игнорировать все скрытые файлы, выполнив:

find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'
tripleee
19 февраля 2016 в 05:59
0

Скобки кажутся излишними. Ранее у него была ошибка форматирования, которая делала его непригодным для использования (рендеринг Markdown съедал некоторые символы из регулярного выражения).

avatar
Christoff Erasmus
25 апреля 2014 в 21:56
1

Для Qshell (qsh) на IBMi, а не bash, как помечено OP.

Ограничения команд qsh:

  • find не имеет опции -print0
  • xargs не имеет опции -0
  • sed не имеет опции -i

Таким образом, решение в qsh:

    PATH='your/path/here'
    SEARCH=\'subdomainA.example.com\'
    REPLACE=\'subdomainB.example.com\'

    for file in $( find ${PATH} -P -type f ); do

            TEMP_FILE=${file}.${RANDOM}.temp_file

            if [ ! -e ${TEMP_FILE} ]; then
                    touch -C 819 ${TEMP_FILE}

                    sed -e 's/'$SEARCH'/'$REPLACE'/g' \
                    < ${file} > ${TEMP_FILE}

                    mv ${TEMP_FILE} ${file}
            fi
    done

Предостережения:

  • Решение исключает обработку ошибок
  • Not Bash, помеченный OP
tripleee
18 февраля 2016 в 06:38
0

Это вызывает некоторые неприятные проблемы с цитированием, а также с чтением строк с for.

avatar
Anatoly
13 марта 2014 в 17:05
334

Самый простой способ для меня -

grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'
phyatt
13 ноября 2015 в 21:36
47

Это особенно хорошо работает, когда вам нужно исключить каталоги, например, с .svn. Например: grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'

Ben Butterworth
13 октября 2020 в 14:07
14

В macOS sed -i вызывает sed: 1: "file_path": invalid command code .. Это потому, что -i - это другой флаг в macOS. Нашел grep -rl old . | xargs sed -i "" -e 's/old/new/g' работает. Я нашел этот полезным

TomDane
25 ноября 2020 в 20:35
1

Если вы используете скомпилированный язык и не хотите проверять двоичные файлы, вы можете передать флаг I, например grep -Irl oldtext . | xargs sed -i 's/oldtext/newtext/g'

rjurney
24 апреля 2021 в 19:20
0

В проекте git обязательно используйте git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g', чтобы избежать поиска зависимостей (которые, вероятно, игнорируются через .gitignore) :) Отличное решение! @phyatt, это лучший способ сделать это.

Mushrankhan
31 мая 2021 в 15:15
0

используя MACOS и разочарованный, почему он не работает -> попробуйте -> grep -rl 'SEARCHSTRING' ./ | LC_ALL=C xargs sed -i '' 's/SEARCHSTRING/REPLACESTRING/g'

avatar
Jimmy Kane
10 февраля 2014 в 19:07
18

И еще один приятный вкладыш в качестве дополнения. Используя git grep.

git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"
mahemoff
6 апреля 2014 в 21:22
3

Хорошая идея, если вы работаете внутри репозитория git, поскольку вы не рискуете перезаписать .git / contents (как указано в комментариях к другому ответу).

Paul Rougieux
18 декабря 2019 в 16:14
1

Спасибо, я использую его как функцию bash. refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" } Использование, например, чтобы заменить слово "меч": refactor word sword, а затем проверить, что он сделал с помощью git diff.

avatar
I159
31 января 2014 в 12:00
77

Все приемы почти одинаковы, но мне нравится вот этот:

find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} +
  • find <mydir>: поиск в каталоге.

  • -type f:

    Тип файла: обычный файл

  • -exec command {} +:

    Этот вариант действия -exec запускает указанную команду для выбранных файлов, но командная строка создается путем добавления имя каждого выбранного файла в конце; общее количество вызовов команды будет намного меньше, чем количество совпадающие файлы. Командная строка строится почти так же, как xargs строит свои командные строки. Только один экземпляр В команде допускается использование символа {}. Команда выполняется в начальном каталоге.

avatar
petrus4
5 ноября 2013 в 17:06
4
#!/usr/local/bin/bash -x

find * /home/www -type f | while read files
do

sedtest=$(sed -n '/^/,/$/p' "${files}" | sed -n '/subdomainA/p')

    if [ "${sedtest}" ]
    then
    sed s'/subdomainA/subdomainB/'g "${files}" > "${files}".tmp
    mv "${files}".tmp "${files}"
    fi

done
avatar
Robert Lujo
3 сентября 2013 в 10:00
45

Для меня проще всего запомнить https://coderhelper.com/a/2113224/565525, то есть:

sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)

ПРИМЕЧАНИЕ : -i '' решает проблему OSX sed: 1: "...": invalid command code .

ПРИМЕЧАНИЕ : Если файлов слишком много для обработки, вы получите Argument list too long. Обходной путь - используйте find -exec или xargs решение, описанное выше.

avatar
Stenemo
20 июня 2013 в 13:06
1

для изменения нескольких файлов (и сохранения резервной копии как *.bak):

perl -p -i -e "s/\|/x/g" *

возьмет все файлы в каталоге и заменит | на x называется «Perl pie» (простой как пирог)

PKHunter
24 августа 2015 в 13:04
0

Однако не рекурсивно через каталоги.

Stenemo
31 августа 2015 в 16:57
0

к нему можно подключиться по конвейеру, что делает его очень настраиваемым, в том числе через каталоги. josephscott.org/archives/2005/08/… и unix.stackexchange.com/questions/101415/…

avatar
Henno
10 апреля 2011 в 00:25
8

Мне просто это было нужно, и я был недоволен скоростью доступных примеров. Так что я придумал свой:

cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

Ack-grep очень эффективно находит нужные файлы. Эта команда быстро заменила ~ 145 000 файлов, тогда как другие заняли так много времени, что я не мог дождаться их завершения.

trusktr
2 ноября 2012 в 19:57
0

Хорошо, но grep -ril 'subdomainA' * далеко не так быстро, как grep -Hr 'subdomainA' * | cut -d: -f1.

user2284570
3 августа 2014 в 23:05
0

@Henno: только один вопрос: как я могу исключить двоичные файлы (исполняемые файлы) ?

Henno
4 августа 2014 в 05:03
0

ack-grep сделает это автоматически.

user2284570
4 августа 2014 в 09:24
0

@Henno: Включает ли он сценарии оболочки?

Henno
4 августа 2014 в 16:13
0

да. Вот полный список поддерживаемых типов файлов: yondgrep.com/documentation

avatar
RikHic
28 июня 2010 в 12:09
4

Попробуйте это:

sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *`
sdaau
5 марта 2011 в 00:00
1

Привет @RikHic, хороший совет - думал о чем-то вроде этого; к сожалению, это форматирование, приведенное выше, не совсем удачно :) Так что я попробую с предварительным тегом (не работает) - так что с экранированием обратных кавычек: sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' /home/www/*` - это все равно не выглядит все тоже хорошо, но должен пережить копипасту :) Ура!

avatar
Vijay
22 октября 2009 в 09:40
0

Более простой способ - использовать следующую команду в командной строке

find /home/www/ -type f|xargs perl -pi -e 's/subdomainA\.example\.com/subdomainB.example.com/g' 
avatar
John Zwinck
18 октября 2009 в 19:34
286

Примечание : не запускайте эту команду в папке, содержащей репозиторий git - изменения в .git могут повредить ваш индекс git.

find /home/www/ -type f -exec \
    sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

По сравнению с другими ответами здесь, это проще, чем большинство, и использует sed вместо perl, что и было задано в исходном вопросе.

Nathan Craike
23 марта 2012 в 01:29
53

Обратите внимание, что если вы используете BSD sed (в том числе в Mac OS X), вам необходимо указать явный аргумент пустой строки для параметра sed -i. например: sed -i '' 's/original/replacement/g'

reducing activity
22 марта 2021 в 15:48
0

Как я могу изменить его, чтобы исключить подпапку .git?

avatar
unutbu
18 октября 2009 в 16:40
12
find /home/www/ -type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

find /home/www/ -type f выведет список всех файлов в / home / www / (и его подкаталогах). Флаг «-exec» указывает команде find выполнить следующую команду для каждого найденного файла.

perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

- это команда, выполняемая для файлов (для множества одновременно). {} заменяется именами файлов. + в конце команды указывает find создать одну команду для нескольких имен файлов.

Согласно справочной странице find: "Командная строка построена примерно так же, как xargs создает свои командные строки. "

Таким образом, можно достичь своей цели (и обрабатывать имена файлов, содержащие пробелы) без использования xargs -0 или -print0.

avatar
Nikita Fedyashev
17 октября 2009 в 21:32
912
find /home/www \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'

-print0 указывает find печатать каждый результат, разделенный нулевым символом, а не новой строкой. В том маловероятном случае, если в вашем каталоге есть файлы с символами новой строки в именах, это все равно позволяет xargs работать с правильными именами файлов.

\( -type d -name .git -prune \) - это выражение, которое полностью пропускает все каталоги с именем .git. Вы можете легко расширить его, если используете SVN или имеете другие папки, которые хотите сохранить - просто сравните с другими именами. Это примерно эквивалентно -not -path .git, но более эффективно, потому что вместо проверки каждого файла в каталоге он полностью его пропускает. -o после него требуется из-за того, как -prune на самом деле работает.

Для получения дополнительной информации см. man find.

elrobis
5 июля 2020 в 16:12
1

Это сработало для меня, и мой случай заключался в поиске / замене значений IP-адреса. Однако вопрос к галерее: почему точки экранируются для первого значения subdomainA\.example\.com, но не для второго значения sudomainB.example.com? Я выполнил его в предложенном формате, и, похоже, он отлично справился со своей задачей, но мне любопытно, почему экранирование представлено только для первого строкового шаблона.

Rafis Ganeev
27 октября 2020 в 09:09
0

Этот сценарий остановится, не дойдя до конца, с ошибкой Permission denied, если один из файлов имеет неизменяемый флаг. Лучше использовать -exec sed -i ... {} \; вместо трубы.

KaiserKatze
2 декабря 2020 в 15:53
0

Я часто использую find . -type f -print0 | xargs -0 sed -i -e 's/\r$//' для рекурсивной замены всех CRLF на LF в файлах в определенном каталоге.

Yu Shen
27 мая 2021 в 16:00
0

Это работает для Ubuntu с мая 2021 года.

Mushrankhan
31 мая 2021 в 15:14
0

используя MACOS и разочарованный, почему он не работает -> попробуйте -> find . \( ! -regex '.*/\..*' \) -type f | LC_ALL=C xargs sed -i '' 's/foo/bar/g'

avatar
Employed Russian
17 октября 2009 в 21:13
39
cd /home/www && find . -type f -print0 |
  xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'