Замена строк в файлах на основе определенных критериев поиска является очень распространенной задачей. Как я могу
- заменить строку
foo
сbar
во всех файлов в текущем каталоге? - сделать то же самое рекурсивно для подкаталогов?
- заменить только если имя файла совпадает с другой строкой?
- заменить только если строка найдена в определенном контексте?
- заменить, если строка находится на определенном номере строки?
- заменить несколько строк одной и той же заменой
- заменить несколько строк с различными заменами
text-processing
awk
sed
perl
Тердон
источник
источник
Ответы:
1. Замена всех вхождений одной строки на другую во всех файлах в текущем каталоге:
Это для случаев, когда вы знаете, что каталог содержит только обычные файлы и что вы хотите обработать все не скрытые файлы. Если это не так, используйте подходы в 2.
Все
sed
решения в этом ответе предполагают GNUsed
. Если вы используете FreeBSD или OS / X, замените-i
на-i ''
. Также обратите внимание, что использование-i
коммутатора с любой версиейsed
имеет определенные последствия для безопасности файловой системы и нежелательно в любом сценарии, который вы планируете распространять любым способом.Не рекурсивные файлы только в этом каталоге:
(
perl
один не удастся для имен файлов, заканчивающихся на|
или пробел) ).Рекурсивные, обычные файлы ( включая скрытые ) в этом и всех подкаталогах
Если вы используете zsh:
(может потерпеть неудачу, если список слишком большой, смотрите,
zargs
чтобы обойти).Bash не может напрямую проверять наличие обычных файлов, необходим цикл (фигурные скобки не задают параметры глобально):
Файлы выбираются, когда они являются фактическими файлами (-f), и они доступны для записи (-w).
2. Заменить, только если имя файла совпадает с другой строкой / имеет конкретное расширение / имеет определенный тип и т.д .:
Не рекурсивные файлы только в этом каталоге:
Рекурсивные, обычные файлы в этом и всех подкаталогах
Если вы используете bash (в скобках избегайте глобальных настроек):
Если вы используете zsh:
В
--
Подачи сказать ,sed
что больше флагов не будет дано в командной строке. Это полезно для защиты от имен файлов, начинающихся с-
.Если файл имеет определенный тип, например, исполняемый (см.
man find
Дополнительные параметры):zsh
:3. Заменить, только если строка найдена в определенном контексте
Замените
foo
наbar
только, если естьbaz
позже в той же строке:В
sed
, используя\( \)
сохраняет все , что в скобках , а затем вы можете получить к нему доступ\1
. Есть много вариантов этой темы, чтобы узнать больше о таких регулярных выражениях, смотрите здесь .Заменить
foo
сbar
только еслиfoo
находится на 3 - й колонке (поле) входного файла (при условии , разделенные пробелами поля):(требуется
gawk
4.1.0 или новее).Для другого поля просто используйте
$N
гдеN
номер поля интереса. Для другого разделителя полей (:
в этом примере) используйте:Другое решение с использованием
perl
:ПРИМЕЧАНИЕ: оба решения
awk
иperl
решения будут влиять на интервалы в файле (удаляйте начальные и конечные пробелы и преобразуйте последовательности пробелов в один пробел в этих совпадающих строках). Для другого поля используйте$F[N-1]
гдеN
вы хотите номер поля, а для другого использования разделителя полей ($"=":"
устанавливает выходной разделитель полей:
):Заменить
foo
сbar
только на 4 - й строке:4. Несколько операций замены: заменить на разные строки
Вы можете комбинировать
sed
команды:Помните, что порядок имеет значение (
sed 's/foo/bar/g; s/bar/baz/g'
будет замененfoo
наbaz
).или Perl команды
Если у вас есть большое количество шаблонов, проще сохранить ваши шаблоны и их замены в
sed
файле сценария:Или, если у вас слишком много пар шаблонов, чтобы описанное выше было возможно, вы можете прочитать пары шаблонов из файла (два шаблона с разделением пробелами, $ pattern и $ replace, на строку):
Это будет довольно медленно для длинных списков шаблонов и больших файлов данных, поэтому вы можете захотеть прочитать шаблоны и
sed
вместо них создать скрипт. Далее предполагается, что разделитель <пробел> разделяет список пар MATCH <пробел> ЗАМЕНА, встречающихся в файле по одной на строкуpatterns.txt
:Приведенный выше формат в основном произвольный и, например, не допускает использование <пробела> в MATCH или REPLACE . Хотя метод очень общий: в основном, если вы можете создать выходной поток, который выглядит как
sed
скрипт, то вы можете использовать этот поток какsed
скрипт, указавsed
файл скрипта как-
stdin.Вы можете комбинировать и объединять несколько скриптов аналогичным образом:
POSIX
sed
объединит все сценарии в один в порядке их появления в командной строке. Ни один из них не должен заканчиваться на\n
ewline.grep
может работать так же:При работе с фиксированными строками в качестве шаблонов рекомендуется избегать метасимволов регулярных выражений . Вы можете сделать это довольно легко:
5. Несколько операций замены: заменить несколько шаблонов одной строкой
Заменить все
foo
,bar
илиbaz
сfoobar
или же
источник
zsh
. Конечно, добавьтеzsh
информацию, но нет причин удалять bash. Также я знаю, что использование оболочки для обработки текста не идеально, но есть случаи, когда это необходимо. Я отредактировал более качественную версию моего оригинального скрипта, которая будет создаватьsed
скрипт вместо фактического использования цикла оболочки для анализа. Это может быть полезно, например, если у вас есть несколько сотен пар паттернов.(.)
классификатора globbing, поэтому здесь его нельзя использовать. (вам не хватает некоторых - также). Цикл for является неправильным (отсутствует -r) и означает несколько проходов в файлах и не добавляет никаких преимуществ по сравнению со сценарием sed.--
послеsed -i
и перед командой замены?-
. Его использование гарантирует, что команды будут работать с файлами с такими именами, как-foo
. Без этого-f
будет разбираться как вариант..git
каталоге и фактически испортят вашу проверку. Лучше работать в / на определенных каталогах по имени.Хороший т е пл acement инструмента Linux является RPL , которая первоначально была написана для проекта Debian, так что он доступен с
apt-get install rpl
любым Debian производного дистрибутива, и может быть для других, но в противном случае вы можете скачатьtar.gz
файл в SourgeForge .Простейший пример использования:
Обратите внимание, что если строка содержит пробелы, она должна быть заключена в кавычки. По умолчанию
rpl
заботятся о заглавных буквах, но не о полных словах , но вы можете изменить эти значения по умолчанию с помощью параметров-i
(игнорировать регистр) и-w
(целые слова). Вы также можете указать несколько файлов :Или даже укажите extensions (
-x
) для поиска или даже рекурсивный поиск (-R
) в каталоге:Вы также можете искать / заменять в интерактивном режиме с
-p
опцией (подсказка):Выходные данные показывают количество замененных файлов / строк и тип поиска (регистр в / чувствительном, целые / частичные слова), но он может быть беззвучным с опцией
-q
( тихий режим ) или даже более подробно, перечисляя номера строк, которые содержат совпадения каждого файла и каталога с опцией-v
( подробный режим ).Другие варианты, которые стоит помнить , являются
-e
(честь е Scapes) , которые позволяютregular expressions
, так что вы можете осуществлять поиск и вкладки (\t
), новые строки (\n
) и т.д.. Даже вы можете использовать-f
для принудительного разрешения (конечно, только когда у пользователя есть права на запись) и-d
сохранить время модификации`).Наконец, если вы не уверены, что именно сделает, используйте
-s
( режим имитации ).источник
Как сделать поиск и заменить несколько файлов предлагает:
Мои лучшие результаты получены от использования Perl и grep (чтобы убедиться, что файл имеет выражение поиска)
источник
Вы можете использовать Vim в режиме Ex:
источник
Я использовал это:
Список всех файлов, которые содержат
old_string
.Замените новую строку в результате пробелами (чтобы можно было передавать список файлов
sed
.Запустите
sed
эти файлы, чтобы заменить старую строку новой.Обновление: приведенный выше результат не удастся для имен файлов, которые содержат пробелы. Вместо этого используйте:
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
источник
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
заставит его иметь дело с произвольными именами файлов.С точки зрения пользователя, это хороший и простой инструмент Unix, который отлично справляется со своей задачей
qsubst
. Например,заменит
foo
сbar
во всех моих файлах C. Приятной особенностью является то, чтоqsubst
будет выполнять запрос-замену , то есть он будет показывать мне каждое вхождениеfoo
и спрашивать, хочу ли я заменить его или нет. [Вы можете заменить безоговорочно (не спрашивая) с-go
опцией, и есть другие варианты, например,-w
если вы хотите заменить, толькоfoo
когда это целое слово.]Как это получить:
qsubst
был изобретен дер Маусом (из McGill) и опубликован на comp.unix.sources 11 (7) в августе 1987 года. Существуют обновленные версии. Например, версия NetBSDqsubst.c,v 1.8 2004/11/01
компилируется и отлично работает на моем Mac.источник
Мне нужно было что - то , что бы обеспечить всухую вариант и будет работать рекурсивно с Glob, и после попытки сделать это с
awk
иsed
я отказался и вместо этого сделал это в питона.Скрипт ищет рекурсивно все файлы , соответствующие шаблон Глоба (например
--glob="*.html"
) для регулярных выражений и заменяет регулярное выражение замены:Каждый длинный вариант , такие как
--search-regex
есть соответствующий короткий вариант, то есть-s
. Запустите с,-h
чтобы увидеть все варианты.Например, это перевернет все даты с
2017-12-31
на31-12-2017
:источник
globstar
опцию bash (или эквивалент вашей оболочки) и**
globs, либоfind
. Для пробного запуска просто используйтеsed
. Если вы не используете-i
опцию, она не будет вносить никаких изменений. Для резервного копирования используйтеsed -i.bak
(илиperl -i .bak
); для файлов, которые не совпадают, используйтеgrep PATTERN file || echo file
. И почему в мире вам нужно, чтобы python расширял глобус, а не позволял оболочке это делать? Почемуscript.py --glob=foo*
вместо простоscript.py foo*
?sed
иawk
хорошо и не желая тратить дополнительное время на их освоение, (4) удобочитаемость, (5) это решение также будет работать на не-posix системах (не то, что мне нужно, но кто-то еще может).ripgrep (имя команды
rg
) -grep
инструмент, но также поддерживает поиск и замену.rg
не поддерживает опцию на месте, поэтому вам придется сделать это самостоятельноСм. Документацию по регулярным выражениям Rust для ознакомления с синтаксисом и функциями регулярного выражения
-P
Переключатель позволит PCRE2 аромат.rg
поддерживает Unicode по умолчанию.Например
grep
, эта-F
опция позволит сопоставить фиксированные строки, что, по моему мнению, такжеsed
должно быть реализовано.Еще одна удобная опция,
-U
которая позволяет многострочное соответствиеrg
может обрабатывать файлы в стиле DOSЕще одним преимуществом
rg
является то, что он может быть быстрее, чемsed
источник