Обработка текста с помощью регулярных выражений

LinuxBeginner
Практиковаться сейчас

Введение

Регулярное выражение описывает текст по его структуре, а не по одной точной строке. Один и тот же язык шаблонов используется во многих инструментах Linux, но каждый инструмент применяет его по-своему: grep выбирает или извлекает совпадения, sed преобразует поток, а awk объединяет шаблоны с действиями, учитывающими поля.

Сначала вы познакомитесь с якорями и классами символов, затем перейдёте к расширенным повторениям и извлечению совпадений, научитесь предварительно просматривать преобразования перед сохранением и завершите работу выбором полей и агрегацией. Шаблоны заключаются в кавычки, чтобы оболочка передавала специальные символы текстовому инструменту, а не интерпретировала их самостоятельно.

Сопоставление строк с базовой структурой регулярных выражений

На этом этапе вы будете использовать обычный текст, якоря и классы символов для описания позиций во всей строке.

Просмотрите учебный файл:

cd /home/labex/project/regex-lab
nl -ba contacts.txt

Обычный текст сопоставляется в любом месте строки:

grep 'active' contacts.txt

Символ ^ привязывает шаблон к началу строки, а $ — к её концу. Найдите запись Alice и записи, заканчивающиеся двузначным числом:

grep '^Alice|' contacts.txt
grep '[0-9][0-9]$' contacts.txt

В квадратных скобках класс символов сопоставляется с одним символом. [ABC] означает A, B или C:

grep '^[ABC]' contacts.txt | tee abc-contacts.txt

Эта команда выводит записи Alice, Bob и Carol. Также сохраните числовые совпадения, привязанные к концу строки:

grep '[0-9][0-9]$' contacts.txt > two-digit-values.txt

Использование расширенных регулярных выражений и извлечение совпадений

На этом этапе вы будете использовать расширенные регулярные выражения для задания альтернатив и повторений, а затем извлечёте только совпавшую подстроку.

Команда grep -E включает такие операторы, как + (один или более символов), ? (ноль или один символ) и | (альтернатива). Найдите полные поля статуса active или pending:

cd /home/labex/project/regex-lab
grep -E '\|(active|pending)\|' contacts.txt

Шаблон, похожий на адрес электронной почты, можно собрать из отдельных частей:

  • [[:alnum:]._-]+ сопоставляется с одним или несколькими допустимыми символами локальной части;
  • @ — обычный символ;
  • [[:alnum:].-]+ сопоставляется с содержимым домена;
  • \.[[:alpha:]]{2,} сопоставляется с точкой и суффиксом из двух или более букв.

Используйте -o, чтобы выводить только совпавшие подстроки:

grep -Eo '[[:alnum:]._-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}' contacts.txt | tee emails.txt

Пронумеруйте строки с совпадениями и подсчитайте количество извлечённых адресов:

grep -En '\|(active|pending)\|' contacts.txt
wc -l < emails.txt | tr -d ' ' > email-count.txt
cat email-count.txt

Некорректная запись dave_at_example.com не сопоставляется, потому что в ней нет символа @.

Предварительный просмотр преобразований с помощью Sed

На этом этапе вы будете преобразовывать поток с помощью sed, не изменяя входной файл.

Подстановка имеет вид s/pattern/replacement/flags. Замените только первый символ a в каждой строке, а затем замените все строчные a с помощью флага g:

cd /home/labex/project/regex-lab
sed 's/a/A/' contacts.txt
sed 's/a/A/g' contacts.txt

Используйте другой разделитель, если сам текст содержит косые черты или другой разделитель делает команду понятнее. Замените домены адресов электронной почты на redacted.invalid:

sed -E 's#@[[:alnum:].-]+\.[[:alpha:]]{2,}#@redacted.invalid#g' contacts.txt

Адреса sed определяют, к каким строкам применяется команда. Выполните замену статуса только в строках, содержащих точное поле |inactive|:

sed '/|inactive|/s/|inactive|/|disabled|/' contacts.txt | tee contacts-preview.txt

Убедитесь, что в исходном файле по-прежнему содержится inactive:

grep '|inactive|' contacts.txt

Создание очищенного файла с помощью Sed

На этом этапе вы объедините несколько команд sed и сохраните преобразованный поток в новый файл.

Заголовок в services.csv должен остаться без изменений. В строках данных замените warn на warning и добавьте суффикс ms к последнему числовому полю. Параметр -e задаёт несколько команд, а адрес 2,$ ограничивает их применение строками со второй до последней:

cd /home/labex/project/regex-lab
sed -E -e '2,$ s/,warn,/,warning,/' -e '2,$ s/([0-9]+)$/\1ms/' services.csv | tee services-clean.csv

Здесь круглые скобки захватывают последние цифры, а \1 повторно использует это совпадение в замене.

Сравните исходный и новый файлы:

diff -u services.csv services-clean.csv || true

Ненулевой код завершения diff ожидаем, поскольку вывод намеренно изменился; || true позволяет продолжить скопированную последовательность команд.

Выбор полей и агрегация с помощью Awk

На этом этапе вы будете использовать awk, когда задача требует одновременно учитывать структуру полей и выполнять вычисления.

Параметр -F, задаёт запятую в качестве разделителя входных данных. Выведите службу и статус только для строк данных; NR содержит номер текущей записи:

cd /home/labex/project/regex-lab
awk -F, 'NR > 1 {print $1, $2}' services.csv

Выберите строки, в которых числовое третье поле больше 200:

awk -F, 'NR > 1 && $3 > 200 {print $1, $3}' services.csv | tee slow-services.txt

Накопите сумму и количество значений, а затем вычислите среднее в блоке END. printf управляет числовым форматом:

awk -F, 'NR > 1 {sum += $3; count++} END {printf "average_latency=%.1f\n", sum/count}' services.csv | tee latency-summary.txt

Шаблоны Awk определяют, для каких записей выполняется действие; поля, такие как $1 и $3, делают вычисления со структурированными данными понятными.

Итоги

Вы составили шаблоны регулярных выражений с якорями, классами, альтернативами и повторениями; использовали grep для выбора и извлечения; применяли sed для предварительного просмотра и сохранения преобразований; а также использовали awk для выбора и агрегации с учётом полей. В следующем испытании вам нужно будет применить эти идеи без готовой последовательности команд.