Во всех рассматривавшихся до сих пор примерах проводился поиск обычных строк из букв и чисел. Но команда
grep
может искать и более сложные шаблоны: она интерпретирует выражения согласно простому языку для описания строк. С технической точки зрения шаблон представляет в некоторой степени ограниченную форму спецификаций строк, называемую регулярным выражением. Команда интерпретирует такие же регулярные выражения, как и редактор
ed
. На самом деле, эта команда была создана (за один вечер) прямым редактированием
ed
.
Регулярные выражения характеризуются тем, что ряду символов, таким, как
*
и т.п., приписывается специальное значение, используемое интерпретатором. Есть еще несколько метасимволов, но, к сожалению, с различными значениями. В табл. 4.1 показаны все метасимволы регулярных выражений, и мы кратко их здесь рассмотрим.
с
| Любой неспециальный символ c соответствует самому себе |
\c
| Указание убрать любое специальное значение символа c
|
^
| Начало строки |
$
| Конец строки |
.
| Любой одиночный символ |
[...]
| Любой символ из ...; допустимы диапазоны типа a-z
|
[^...]
| Любой символ не из ... ; допустимы диапазоны |
\n
| Строка, соответствующая n-му выражению \(...\) (только для grep ) |
r*
| Нуль или более вхождений r
|
r+
| Одно или более вхождений r (только для egrep) |
r?
| Нуль или одно вхождение r (только для egrep) |
r1r2
| За r1 следует r2
|
r1|r2
| r1 или r2 (только для egrep) |
\(r\)
| Помеченное регулярное выражение r (только для grep ); может быть вложенным |
(r)
| Регулярное выражение r (только для grep); может быть вложенным |
| Никакое регулярное выражение не соответствует концу строки |
Таблица 4.1: Регулярные выражения
grep
и egrep
(в порядке убывания приоритета)
Метасимволы
^
и
$
привязывают шаблон к началу (
^
) или концу (
$
) строки. Например,
$ grep From $MAIL
ищет строки, содержащие
From
в вашей почтовой посылке, но
$ grep '^From' $MAIL
выдает строки, начинающиеся с
From
, которые, вероятнее всего, будут заглавными строками сообщений. Метасимволы регулярных выражений пересекаются с метасимволами интерпретатора, поэтому всегда имеет смысл заключать шаблоны команды
grep
в апострофы.
Команда
grep
допускает классы символов, подобные тем, что используются интерпретатором: так,
[a-z]
задает любую строчную букву. Но есть и различия — если класс символов команды
grep
начинается с символа слабого ударения то шаблон задает любой символ, кроме входящих в данный класс. Значит,
[^0-9]
задает любой символ, кроме цифры. Как и в интерпретаторе, обратная дробная черта экранирует символы
]
и
-
в классе символов, но команды
grep
и
ed
требуют, чтобы эти символы использовались там, где их значение недвусмысленно. Например, шаблон
[][-]
задает открывающую или закрывающую квадратную скобку либо знак минус.
Точка
'.'
эквивалентна
'?'
в интерпретаторе: она задает любой символ. (Точка, по всей видимости, есть символ, назначение которого различно для разных программ.) Ниже приводятся два примера:
$ ls -l | grep '^d'
Список имен вложенных каталогов
$ ls -l | grep '^.......rw'
Список файлов, доступных всем для чтения и записи
Символ
'^'
и семь точек задают любые семь символов в начале строки; в случае применения к выходному потоку команды
ls -l
задается любая строка права доступа.
Операция "повторитель" (
'*'
) применима в выражении к предваряющему ее символу или метасимволу (включая класс символов), и вместе они обозначают любое число вхождений символа или метасимвола. Например,
x*
задает последовательность букв
x
произвольной длины,
[a-zA-Z]*
— любую строку букв,
.*
— все до конца строки, а
.*x
— все до последнего символа
x
в строке включительно. Необходимо отметить несколько важных моментов, связанных с повторителем. Во-первых, повторитель действует только на один символ, поэтому
xy*
соответствует
x
, за которым идут
yy...
, но не последовательности типа
xyxyxy
. Во-вторых, любое число включает нуль, поэтому если вы хотите, чтобы символ присутствовал, в шаблоне его нужно повторить. Например, правильным выражением, задающим строку букв, является такое:
[a-zA-Z][a-zA-Z]*
(буква, за которой следует нуль или более букв). Регулярное выражение
.*
соответствует —
*
, т.е. метасимволу интерпретатора, используемому для имен файлов.