




Вы имеете в виду поиск и замену строки во всех файлах, соответствующих 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
Если ваш 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/' *
for i in *; do ... избыточен, sed может принимать список файлов в качестве аргументов.
@Jens, почему бы не улучшить этот ответ, добавив свой собственный пример к приведенному выше?
Переменные всегда следует указывать в кавычках for i in *; do; sed -i 's/foo/bar/g' "$i"; done.
Судя по приведенному вами примеру, это именно то, что вам нужно:
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 для поиска - это удобный способ показать, какие файлы были сопоставлены. Все это зависит от конкретных версий этих инструментов в вашей системе.
Предупреждение для пользователей cygwin. Комбинация find и sed, похоже, меняет права пользователя на файлы, которые передаются через поток. Это можно просто исправить, используя команду chmod -R 644 * из того же уровня каталога, который использовался при работе find / sed.
Слово предупреждения людям, которые не хотят использовать аргумент -i: если вы его не используете, он не сработает (не спрашивайте меня, почему)
@knocte -i сообщает sed изменить файл, в противном случае он просто выводит измененную версию на стандартный вывод. Если вы не хотите, чтобы файл .bak создавался, просто опустите часть «.bak», -i тоже работает автономно.
В OSX вам нужно указать команде find каталог для запуска, например find . -name '*.html' или find directoryname/ -name '*'.
мне нужно было добавить -e, иначе он подумал, что часть 's ...' была суффиксом sed -ie 's/foo/bar/g' *
"Foo", "bar" - это просто слова (для точного совпадения) или регулярное выражение?
@KrishPrabakar регулярное выражение
Мне нравится и я использовал вышеуказанное решение или общесистемный поиск и замену среди тысяч файлов:
find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;
Я предполагаю с помощью '* .htm?' вместо .html он ищет и находит как файлы .htm, так и .html.
Я заменяю .bak более общесистемной тильдой (~), чтобы упростить очистку файлов резервных копий.
find . -type f -print0 | xargs -0 <sed/perl/ruby cmd> будет обрабатывать несколько пространственных имен файлов одновременно, загружая по одному интерпретатору на пакет. Намного быстрее.
@knocte, «cmd» - это токен для всей команды поиска и замены для любого выбранного инструмента. Этот ответ отвечает на вопрос о том, как бороться с пустыми пространствами, содержащими имена файлов.
Это работает с использованием grep без использования perl или find.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
xargs не имеет -i в OSX или BSD openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man1/… вы имели в виду использовать верхний регистр «I»?
Я не знал, что -i не работает с другими ОС. У меня работает на убунту.
Моя справочная страница xargs (в Ubuntu) говорит, что -i устарел, и вместо этого нужно использовать -I. Итак, следует сказать: grep -rli 'old-word' * | xargs -I filepath sed -i 's/old-word/new-word/g' filepath
Уже дан ответ об использовании найти и sed
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, который я написал некоторое время назад для некоторых более сложные задачи переименования и рефакторинга. Причины, по которым вы можете предпочесть это:
Проверьте README для примеров.
На самом деле это проще, чем кажется.
grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
Очень просто. Если вы хорошо разбираетесь в find, grep, xargs, sed и awk, почти нет ничего невозможного, когда дело доходит до манипулирования текстовыми файлами в bash :)
Ба, не обращайте внимания, этот pymarco уже говорил об этом выше. Оставляю свой ответ для объяснения.
Я думаю, это может быть проблема с файлами / папками, содержащими пробелы.
Can't open Untitled: No such file or directory, <> line 5при попытке "Папка без названия / file.txt".