Бах, не обращай внимания, это пимарко уже освещало это выше. Оставив мой ответ для объяснения.

аюсь найти и заменить строку во всех файлах, соответствующих grep на машине с Linux. У меня есть кое-что из того, что я хочу сделать, но я не уверен, как лучше связать их всех вместе.

grep -n 'foo' * выдаст мне вывод в виде:

[filename]:[line number]:[text]

Для каждого файла, возвращаемого grep, я хотел бы заменить «foo» на «bar» и записать результат обратно в файл. Есть ли хороший способ сделать это? Может быть, модный трубопровод?

 Eineki22 янв. 2009 г., 23:57
Вы можете перефразировать свой вопрос? Мне не понятно ...
 Keltia23 янв. 2009 г., 00:00
Мне тоже непонятно ...

Ответы на вопрос(8)

find . -type f -print0 | xargs -0 <sed/perl/ruby cmd> обрабатывает имена файлов, содержащиеся в нескольких пробелах, одновременно загружая один интерпретатор на пакет. Намного быстрее.

 knocte25 сент. 2013 г., 15:38
где тут фу ??
 Tony Adams03 нояб. 2014 г., 16:44
@knocte, "cmd" - это токен для всей команды поиска и замены для любого выбранного инструмента. Этот ответ отвечает на вопрос о том, как обращаться с именами файлов, содержащими пробелы.

истеме и замена среди тысяч файлов:

find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;

Я предполагаю, что с * .htm? вместо .html он ищет и находит файлы .htm и .html.

Я заменяю .bak более тильдой (~), используемой в более широкой системе, чтобы упростить очистку резервных файлов.

Это на самом деле проще, чем кажется.

grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
grep рекурсивно просматривает ваше дерево (-R) и печатает только имя файла (-l), начиная с текущего каталога (./)он передается в xargs, который обрабатывает их по одному (-n 1), и использует% в качестве заполнителя (-I%) в команде оболочки (sh -c)в команде оболочки сначала печатается имя файла (ls%;)затем sed выполняет встроенную операцию (-i), подстановку ('s /') foo с баром (foo / bar), глобально (/ g) над файлом (снова, представленным в%)

Очень просто. Если вы хорошо разбираетесь в find, grep, xargs, sed и awk, то практически ничего невозможного в том, что касается манипулирования текстовыми файлами в bash :)

 siliconrockstar19 нояб. 2015 г., 04:37
Бах, не обращай внимания, это пимарко уже освещало это выше. Оставив мой ответ для объяснения.

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

sed -i 's/foo/bar/g' *

Он не является рекурсивным (он не сойдет в подкаталоги). Для хорошего решения замены выбранных файлов по всему дереву я бы использовал find:

find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

*.html является выражением, которому должны соответствовать файлы,.bak после-i создает копию исходного файла с расширением .bak (это может быть любое расширение, которое вам нравится) иg в конце выражения sed говорит sed заменить несколько копий в одной строке (а не только в первой).-print найти это удобно, чтобы показать, какие файлы были сопоставлены. Все это зависит от точных версий этих инструментов в вашей системе.

 knocte25 сент. 2013 г., 18:55
спасибо @MattJ, приятно знать
 MattJ25 сент. 2013 г., 18:41
@knocte -i говорит sed изменить файл, иначе он просто печатает измененную версию в стандартный вывод. Если вы не хотите, чтобы файл .bak создавался, просто пропустите часть «.bak», -i тоже работает автономно.
 kaskelotti08 авг. 2013 г., 12:30
Предупреждение для пользователей Cygwin. Команды find и sed, кажется, изменяют права пользователя для файлов, через которые передаются потоки. Это можно просто исправить, используя команду chmod -R 644 * с того же уровня dir, который использовался при работе find / sed.
 Michiel Kauw-A-Tjoe19 июн. 2014 г., 10:06
На OSX вам нужно датьfind например, команда для запуска каталогаfind . -name '*.html' или жеfind directoryname/ -name '*'.
 knocte25 сент. 2013 г., 15:41
Слово предупреждения людям, которые не хотят использовать аргумент -i: если вы его не используете, он не работает (не спрашивайте меня, почему)

Если твойsed(1) имеет-i вариант, затем используйте его так:

for i in *; do
  sed -i 's/foo/bar/' $i
done

Если нет, существует несколько вариантов следующих вариантов в зависимости от того, на каком языке вы хотите играть:

ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
perl -pi.bak -e 's/foo/bar/' *
 cat06 июл. 2016 г., 04:50
Переменные всегда должны быть в кавычкахfor i in *; do; sed -i 's/foo/bar/g' "$i"; done
 Jens01 июн. 2012 г., 10:46
for i in *; do ... избыточно, sed может принимать список файлов в качестве аргументов.
 Magpie25 июн. 2014 г., 13:43
@Jens, почему бы не улучшить этот ответ, добавив собственный пример к приведенному выше?

находить а такжеСЕПГ

find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

наверное стандартный ответ. Или вы могли бы использоватьperl -pi -e s/foo/bar/g' вместоsed команда.

Для наиболее быстрого использования вы можете найти командуRPL легче запомнить. Вот замена (foo -> bar), рекурсивно для всех файлов в текущем каталоге:

rpl -R foo bar .

По умолчанию он недоступен в большинстве дистрибутивов Linux, но быстро устанавливается (apt-get install rpl или похожие).

Однако для более сложных заданий, которые включают регулярные выражения и обратную подстановку или переименование файлов, а также поиск и замену, наиболее общий и мощный инструмент, о котором я знаю, этоreprenНебольшой скрипт на Python, который я написал некоторое время назад для более сложных задач по переименованию и рефакторингу. Причины, по которым вы можете предпочесть это:

Поддержка переименования файлов, а также поиск и замена содержимого файлов (включая перемещение файлов между каталогами и создание новых родительских каталогов).Просмотрите изменения, прежде чем совершать поиск и замену.Поддержка регулярных выражений с режимами обратной подстановки, целых слов, без учета регистра и с сохранением регистра (replace foo -> bar, Foo -> Bar, FOO -> BAR).Работает с множественными заменами, включая перестановки (foo -> bar и bar -> foo) или наборы неуникальных замен (foo -> bar, f -> x).

Проверьте README Например.

или find.

grep -rli 'old-word' * | xargs [email protected] sed -i 's/old-word/new-word/g' @
 Max Wallace25 июн. 2016 г., 15:22
мойxargs manpage (на Ubuntu) говорит, что-i устарела, и использовать-I вместо. Итак, мы должны сказать:grep -rli 'old-word' * | xargs -I filepath sed -i 's/old-word/new-word/g' filepath
 pymarco03 нояб. 2014 г., 17:09
Я не знала-i не работал для других ОС. У меня работает на убунту.
 Tony Adams03 нояб. 2014 г., 16:48
xargs не имеет -i на OSX или BSDopenbsd.org/cgi-bin/man.cgi/OpenBSD-current/man1/... Вы хотели использовать верхний регистр "I"?
Решение Вопроса

соответствующих grep?

perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`

редактировать

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

В настоящее время я в основном используюack-grep как это более удобно для пользователя. Таким образом, приведенная выше команда будет:

perl -p -i -e 's/old/new/g' `ack -l searchpattern`

Для обработки пробелов в именах файлов вы можете запустить:

ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

Вы можете сделать больше сack-grep, Допустим, вы хотите ограничить поиск только файлами HTML:

ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

И если пробел не проблема, он еще короче:

perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files
 Xeoncross06 дек. 2011 г., 21:07
Я думаю, что это может иметь проблемы с файлами / папками, которые содержат пробелы.Can't open Untitled: No such file or directory, <> line 5 при попытке "Untitled Folder / file.txt".

Ваш ответ на вопрос