[Перевод] Кунг-фу стиля Linux: глобальный поиск и замена строк с помощью ripgrep
Даже те, кто пользуется Linux лишь от случая к случаю, вероятно, знают о том, как работать с grep
. При этом не нужно быть экспертом в сфере регулярных выражений для того чтобы без особых сложностей пользоваться grep
для поиска в файлах строк, соответствующих простым последовательностям символов или сложным шаблонам. Конечно, grep
— это отличный инструмент для поиска информации. Но что если нужно что-то найти, а потом — заменить это на что-то другое? Например, может быть, нужно изменить все найденные слова HackADay
на Hackaday
. Тут можно применить sed
, но этой утилитой пользоваться довольно сложно. Для решения этой задачи можно было бы воспользоваться awk
. Но, учитывая то, что речь идёт о языке программирования, использовать его для решения столь простой и распространённой задачи — это, пожалуй, чересчур. Именно идея, заключающаяся в простом решении вышеописанной задачи, и лежит в основе утилиты ripgrep (соответствующая ей команда выглядит как rg
). С помощью rg
можно решать те же задачи, что решает grep
, но при этом — пользоваться более современными регулярными выражениями и, кроме того, не только искать строки, но и выполнять их замену.
Об установке ripgrep
Лучше всего, если вам удастся установить ripgrep
из репозиториев, доступных в вашем дистрибутиве Linux. Когда я попробовал установить ripgrep
в KDE Neon, мне было сообщено, что одну версию ripgrep
можно установить с помощью apt
, а ещё одну, более свежую, можно установить из Snap-пакета. Я — не фанат Snap-пакетов, но я, всё равно, пошёл именно таким путём. Система сообщила, что мне нужно добавить ключ --classic
к команде установки пакета, так как ripgrep
может воздействовать на файлы, находящиеся за пределами Snap-песочницы. Так как смысл существования ripgrep
заключается в том, чтобы менять содержимое файлов, подобное сообщение не показалось мне неожиданным, и я установил ripgrep
.
Простой пример использования ripgrep
Если вы хотите использовать rg
в том же качестве, что и grep
, вы вполне можете так и поступить. Единственное заметное отличие заключается в том, что rg
показывает номер строки при выводе данных в stdout
.
Команда rg выводит номер строки
Если вам это не нужно — запускайте rg
с ключом -N
. Указать то, на что надо заменить найденную строку, можно с помощью ключа -r
.
Использование ключей -N и -r
А что если нужно создавать новые файлы, содержащие изменённые варианты исходных? Для этого можно воспользоваться опцией --passthru
. Благодаря ей в вывод программы попадают все строки исходных файлов — и изменённые, и неизменённые. Потом вывод программы можно записать в новый файл.
С другой стороны, может понадобиться выводить только те части строк, которые совпали с шаблоном, а не строки целиком. Для этого можно воспользоваться опцией -o
. При работе с rg
, кроме того, можно пользоваться и многими другими опциями, похожими на те, что поддерживает grep
. Например, опция -v
позволяет инвертировать поиск — в результате в вывод программы попадут только те строки, в которых не найден заданный шаблон.
Перезапись файлов
Одна из классических проблем, связанная с многозадачной природой Linux, проявляется при попытке перезаписи файла. Например, попробуйте провести следующий эксперимент:
cd /tmp
cp /etc/fstab test.txt
cat test.txt # тут будет выведено много всего
cat test.txt > test.txt
cat test.txt # вот так дела - теперь файл пуст
Но это, тем не менее, обычный сценарий использования rg
. Конечно, выходные данные программы можно отправить во временный файл, а после этого заменить исходный файл на временный. Но это — грубоватое решение задачи. Гораздо изящнее эту задачу можно решить с помощью утилиты sponge
. Эта утилита копирует в файл то, что поступает на её вход. Но при этом она ждёт до тех пор, пока на её вход перестанут поступать новые данные. Для того чтобы в результате вышеописанного эксперимента не получился бы пустой файл, в нём вторую строку снизу надо заменить на такую команду:
cat test.txt | sponge test.txt
Поэтому для того чтобы выполнять замены найденных строк, перезаписывая файлы, нам понадобится примерно такая конструкция:
rg --passthru 'Jen' -r 'Jennifer' invite.txt | sponge invite.txt
Тонкая настройка rg
По умолчанию rg
использует регулярные выражения из Rust. Они известны своей скоростью, но у них, ради достижения высокой производительности, имеются некоторые ограничения. Опция -P
позволяет переключиться на использование регулярных выражений PCRE2. Они имеют больше возможностей, но могут работать медленнее. Ещё один вариант — воспользоваться ключом --engine=auto
. Это приведёт к тому, что rg
, по умолчанию, будет использовать регулярные выражения Rust. А если окажется, что используются какие-то возможности, требующие применения PCRE2, rg
перейдёт на движок PCRE2. Если в команде будет присутствовать несколько регулярных выражений — для обработки всех их будет применён один и тот же движок. Поэтому если среди них будет хотя бы одно регулярное выражение, для обработки которого нужен PCRE2, система использует PCRE2 для обработки всех регулярных выражений.
Применяя движок PCRE2 можно, например, выполнять опережающие проверки, можно использовать обратные ссылки и многие другие продвинутые возможности. Если вам неудобно заключать то, что выглядит как регулярное выражение, в кавычки, в ситуации, когда вам надо найти обычный текст, можете воспользоваться опцией -F
. Это позволит программе, без дополнительных усилий с вашей стороны, воспринимать поисковое выражение как обычный текст.
Использование опции -F
У rg
есть и множество других опций. Посмотрите справку по этой утилите, воспользовавшись ключом --help
. Например, можно искать тексты по шаблонам, охватывающим несколько строк, можно искать данные в бинарных файлах, использовать в качестве признака окончания строки CRLF, выводить заданное количество строк, расположенных до и после найденной строки, фильтровать файлы с использованием внешней программы.
Итоги
Рассмотренная в этом материале утилита rg
— это всего лишь один из простых инструментов, без которых вполне можно обойтись. Но её использование упрощает решение множества распространённых задач. Безусловно, для того чтобы раскрыть весь потенциал инструментов, напоминающих grep
, просто необходимо разобраться с регулярными выражениями. А чтобы изучать их было веселее — можете попробовать специальные кроссворды.
Чем вы пользуетесь для поиска текстовых данных в Linux?