Регулярные выражения Bash

Регулярные выражения Bash


Одним из принципов Unix-систем является широкое использование текстовых данных: конфигурационные файлы, входные и выходные данные программ в *nix часто организованы в виде обычного текста. Регулярные выражения — это мощный инструмент для манипуляции текстовой информацией. В этом гайде разберем тонкости работы с регулярными выражениями Bash, которые помогут вам реализовать весь потенциал командной строки и скриптов в Linux.

Что такое регулярные выражения?

Регулярные выражения — это специальным образом записанные строки, используемые для поиска символьных шаблонов в тексте. Чем-то они похожи на групповые символы в оболочке, но их возможности куда шире. Многие утилиты для работы с текстом в Linux и языки программирования включают в себя механизм регулярных выражений. Здесь возникают проблемы: разные программы и языки оперируют различными диалектами регулярных выражений. В этой статье рассмотрим стандарт POSIX, которому соответствуют большинство утилит в Linux.

Утилита grep

Программа grep — это основной инструмент для работы с регулярными выражениями. Grep анализирует данные со стандартного ввода, ищет совпадения с указанным шаблоном и выводит все подходящие строки. Обычно grep предустановлен в большинстве дистрибутивов. Если хотите потренироваться в использовании регулярных выражений, можете повторять описанные команды в виртуальной машине, либо на арендованном сервере.

Grep имеет следующий синтаксис:

grep [параметры] регулярное_выражение [файл…]


Самый простой случай использования grep — поиск строк, содержащих фиксированную подстроку. В следующем примере grep вывел все строки, содержащие последовательность nologin:

grep nologin /etc/passwd
 
Output:
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
games:x:5:60:games:/usr/games:/usr/sbin/nologin
...

У grep имеются множество параметров. Подробно с ними ознакомиться можно в документации. Приведем ключи, полезные при работе с регулярными выражениями:

Ключ -v — инвертировать критерий. В этом случае grep выводит строки, не содержащие совпадений:

ls /bin | grep -v zip

Output:
[
411toppm
7z
7za
7zr
…

Ключ -i — игнорировать регистр символов.

Ключ -o — выводить не строки, а только совпадения с шаблоном:

ls /bin | grep -o zip

Output:
zip
zip
zip
zip
…

Ключ -w — искать только строки, содержащие все слово, которое составляет шаблон.

ls /bin | grep -w zip

Output:
gpg-zip
zip

Для сравнения та же команда без опции. В вывод также попали строки, содержащие шаблон в качестве подслова в слове.

ls /bin | grep zip

Output
bunzip2
bzip2
bzip2recover
funzip
...

Basic Regular Expressions

Ранее упоминалось, что существует множество диалектов регулярных выражений. В стандарте POSIX рассматриваются два вида реализаций. Первый — Basic Regular Expressions (BRE). Ему соответствуют практически все POSIX-совместимые программы. Второй — Extended Regular Expression (ERE). Этот вид позволяет создавать более сложные регулярные выражения, но поддерживается не всеми утилитами. Для начала рассмотрим особенности BRE.

Метасимволы и литералы

В тексте выше мы уже столкнулись с простыми регулярными выражениями. К примеру, выражение «zip» обозначает строку, соответствующую следующим критериям: в строке не меньше трех символов; в строке присутствуют символы «z», «i», «p», причем именно в таком порядке; между ними нет других символов. Символы, соответствующие сами себе (как «z», «i», «p») называются литералами. Кроме того, существуют другая категория символов, называемая метасимволами. Они применяются для составления различных критериев поиска. К метасимволам в BRE относятся:

^ $ . [ ] * \ -

Чтобы использовать метасимвол в качестве литерала, его нужно экранировать с помощью обратного слэша (\). Обратите внимание, что некоторые метасимволы имеют специальное значение в оболочке. Поэтому при передаче регулярного выражения в аргумент команды его следует заключать в кавычки.

Любой символ

Метасимвол «точка» (.) соответствует любому символу в данной позиции. Например:

ls /bin | grep '.zip'

Output:
bunzip2
bzip2
bzip2recover
funzip
gpg-zip
gunzip
gzip
mzip
p7zip
pbzip2
preunzip
prezip
prezip-bin
streamzip
unzip
unzipsfx

Здесь имеется один важный момент. Программа zip не вошла в вывод, так как метасимвол «точка» увеличил длину обязательного совпадения до четырех символов.

Якорные символы

Символ «карет» (^) и «доллар» ($) в регулярных выражениях играют роль якорей. Это означает, что в их присутствии совпадение с шаблоном возможно, только если оно будет найдено в начале строки (^) или в ее конце ($).

ls /bin | grep '^zip'
Output:
zip
zipcloak
zipdetails
zipgrep
…

  
ls /bin | grep ‘zip$’
Output:
funzip
gpg-zip
gunzip
…

  
ls /bin | grep ‘^zip$’
Output
zip

Регулярное выражение ^$ будет соответствовать пустым строкам.

Множества символов

Кроме описания совпадения с любым символом в заданной позиции (.) в регулярных выражениях имеется возможность описать символ из определенного множества. Делается это с помощью квадратных скобок. В следующем примере ищутся соответствия со строками bzip и gzip:

ls /bin | grep '[bg]zip'
Output:
bzip2
bzip2recover
gzip

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

Если сразу после открывающей квадратной скобки стоит символ карет (^), остальные символы множества интерпретируются как недопустимые в данной позиции. Например:

ls /bin | grep '[^bg]zip'
Output:
bunzip2
funzip
gpg-zip
gunzip
mzip
p7zip
preunzip
prezip
prezip-bin
streamzip
unzip
unzipsfx

Включив отрицание, мы получили список имен файлов, содержащих последовательность zip, которой предшествуют любой символ, кроме b или g. Обратите внимание, что имя zip не было найдено. Символ отрицания не отменяет необходимости присутствия символа в заданной позиции. Кроме того символ карет является отрицанием, только если стоит сразу же после открывающей скобки; в противном случае он теряет свое специальное значение.

С помощью дефиса (-) можно определять диапазоны символов. Так можно выразить любой диапазон символов и даже нескольких таких диапазонов. К примеру нам нужно найти все имена файлов, начинающиеся с буквы или цифры. Делается это так:

ls ~ | grep '^[A-Za-z0-9]'
Output:
backup
bin
Books
Desktop
docker
Documents
Downloads
GNS3
… 


источник


Report Page