Командная строка Linux глобальный поиск и замена
Я пытаюсь найти и заменить строку во всех файлах, сопоставленных grep на машине linux. У меня есть некоторые части того, что я хочу сделать, но я не уверен, как лучше всего связать их вместе.
grep -n 'foo' *
выдаст мне вывод в виде:
[filename]:[line number]:[text]
для каждого файла, возвращенного grep, я хотел бы заменить "foo" на " bar " и записать результат обратно в файл. Есть ли хороший способ сделать это? Может быть, причудливый трубопровод?
8 ответов:
вы имеете в виду поиск и замену строки во всех файлах, сопоставленных grep?
perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`
Edit
поскольку это, кажется, довольно популярный вопрос, я бы обновил.
в настоящее время я в основном использую
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 -i 's/foo/bar/g' *
он не является рекурсивным (он не будет опускаться в подкаталоги). Для хорошей замены решения в выбранных файлах по всему дереву я бы использовал find:
find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
The
*.html
- это выражение, которому должны соответствовать файлы,.bak
после-i
делает копию исходного файла, с a .расширение bak (это может быть любое расширение, которое вам нравится) иg
в конце САС выражение говорит sed заменить несколько копий в одной строке (а не только первый). Элемент
если
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/' *
Мне нравится и используется вышеуказанное решение или общесистемный поиск и замена среди тысяч файлов:
find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;
Я предполагаю, что с '*.htm?- вместо этого .HTML он ищет и находит .хтм И.html файлы похожи.
Я заменить .бак с более широкой системой используется Тильда ( ~ ), чтобы сделать очистку резервных файлов проще.
это работает с использованием grep без необходимости использовать perl или найти.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
find . -type f -print0 | xargs -0 <sed/perl/ruby cmd>
будет обрабатывать несколько имен файлов, содержащихся в пространстве, одновременно загружая один интерпретатор на пакет. Гораздо быстрее.
ответ уже дан при помощи найти и sed
find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
вероятно, стандартный ответ. Или вы могли бы использовать
perl -pi -e s/foo/bar/g'
вместо .для наиболее быстрого использования, вы можете найти команду rpl легче запомнить. Вот замена (foo -> bar), рекурсивно на все файлы в текущем каталоге:
rpl -R foo bar .
по умолчанию он недоступен большинство дистрибутивов Linux, но быстро установить (
apt-get install rpl
или подобные).однако, для более жестких заданий, которые включают регулярные выражения и обратную замену, или переименования файлов, а также поиск и замену, самый общий и мощный инструмент, о котором я знаю,-это repren, небольшой скрипт Python, который я написал некоторое время назад для некоторых более сложных задач переименования и рефакторинга. Причины, по которым вы можете предпочесть это:
- поддержка переименования файлов, а также поиск и замена содержимого файлов (включая перемещение файлов между каталогами и создание новых родительских каталогов).
- см. изменения перед выполнением поиска и замены.
- поддержка регулярных выражений с обратной подстановкой, целыми словами, без учета регистра и сохранением регистра (заменить foo - > bar, Foo -> Bar, FOO -> BAR) режимы.
- работает с несколькими заменами, включая свопы (foo - > bar и bar - > foo) или наборы не уникальных замены (foo - > bar, f -> x).
Проверьте README для примера.
Это на самом деле проще, чем кажется.
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 with bar (foo/bar), глобально (/g) в файле (опять же, представлен %)
легкий и непринужденный. Если вы хорошо разбираетесь в find, grep, xargs, sed и awk, почти нет ничего невозможного, когда речь заходит о манипуляциях с текстовыми файлами в bash:)