Программа grep имеет следующий синтаксис:
grep [параметры] регулярное_выражение [файл...]
В табл. 19.1 перечислены наиболее часто используемые параметры grep.
Таблица 19.1. Параметры команды grep
Параметр
Описание
-i
Игнорировать регистр символов. Требует не различать символы верхнего и нижнего регистра. Аналогично работает параметр --ignore-case
-v
Инвертировать критерий. Обычно grep выводит строки с совпадениями. Этот параметр заставляет grep выводить строки, не содержащие совпадений. Аналогично работает параметр --invert-match
-c
Вывести число совпадений (или «несовпадений») в присутствии параметра -v вместо самих текстовых строк. Аналогично работает параметр --count
-l
Вместо строк с совпадениями выводить только имена файлов с найденными строками. Аналогично работает параметр --files-with-matches
-L
Действует подобно параметру -l, но выводит только имена файлов, где не найдено ни одного совпадения. Аналогично работает параметр --files-without-match
-n
В начале каждой строки с совпадением вывести ее номер в файле. Аналогично работает параметр --line-number
-h
Подавить вывод имен файлов при поиске по нескольким файлам. Аналогично работает параметр --no-filename
Давайте создадим несколько текстовых файлов, чтобы наше исследование grep стало более предметным:
[[email protected] ~]$ ls /bin > dirlist-bin.txt
[[email protected] ~]$ ls /usr/bin > dirlist-usr-bin.txt
[[email protected] ~]$ ls /sbin > dirlist-sbin.txt
[[email protected] ~]$ ls /usr/sbin > dirlist-usr-sbin.txt
[[email protected] ~]$ ls dirlist*.txt
dirlist-bin.txt dirlist-sbin.txt dirlist-usr-sbin.txt
dirlist-usr-bin.txt
Ниже показано, как выполнить простой поиск в нашем списке файлов:
[[email protected] ~]$ grep bzip dirlist*.txt
dirlist-bin.txt:bzip2
dirlist-bin.txt:bzip2recover
В этом примере grep просматривает все перечисленные файлы в поисках строки bzip и находит два совпадения, оба в файле dirlist-bin.txt. Если бы нам достаточно было получить только имена файлов с совпадениями, а не сами совпадения, мы могли бы добавить параметр -l:
[[email protected] ~]$ grep -l bzip dirlist*.txt
dirlist-bin.txt
Напротив, получить список файлов, не содержащих совпадений, можно так:
[[email protected] ~]$ grep -L bzip dirlist*.txt
dirlist-sbin.txt
dirlist-usr-bin.txt
dirlist-usr-sbin.txt
Метасимволы и литералы
Несмотря на то что пока это не очевидно, во всех своих попытках поиска с помощью grep мы использовали регулярные выражения, хотя и очень простые. Регулярное выражение bzip, к примеру, означает, что ему соответствуют только строки в файлах, содержащие не менее четырех символов и среди этих символов присутствуют символы b, z, i и p, следующие именно в таком порядке и между ними отсутствуют какие-либо другие символы. Символы в строке bzip — это литеральные символы, то есть они соответствуют сами себе. Помимо литералов регулярные выражения могут содержать метасимволы, они используются для определения более сложных критериев сопоставления. К метасимволам регулярных выражений относятся следующие символы:
^ $ . [ ] { } - ? * + ( ) |
Все остальные символы считаются литералами. Впрочем, в некоторых случаях символ обратного слеша используется для создания метапоследовательностей, а также для экранирования метасимволов, чтобы они могли интерпретироваться как литералы, а не как метасимволы.
ПРИМЕЧАНИЕ
Как видите, многие метасимволы регулярных выражений имеют также специальное значение для механизма подстановки командной оболочки. Поэтому, передавая регулярные выражения с метасимволами в виде аргументов командной строки, следует заключать их в кавычки, чтобы предотвратить попытки командной оболочки выполнить подстановку вместо них.
Любой символ
Первый метасимвол, который мы рассмотрим, — это символ точки, соответствующий любому символу. Если включить его в регулярное выражение, он будет соответствовать любому символу в данной позиции. Например:
[[email protected] ~]$ grep -h '.zip' dirlist*.txt
bunzip2
bzip2
bzip2recover
gunzip
gzip
funzip
gpg-zip
preunzip
prezip
prezip-bin
unzip
unzipsfx
Здесь выполнен поиск в наших файлах совпадений с регулярным выражением .zip. В полученных результатах имеется пара важных моментов, которые необходимо отметить. Обратите внимание, что программа zip не была найдена. Это объясняется включением в регулярное выражение метасимвола точки, увеличившим длину обязательного совпадения до четырех символов; так как в имени программы zip всего три символа, оно не было найдено. Кроме того, если бы в наших списках имелись имена файлов с расширением .zip, они также были бы найдены, потому что символ точки в расширении файла интерпретировался бы как «любой символ».
Якоря
Символ крышки (^) и знак доллара ($) в регулярных выражениях интерпретируются как якоря. Это означает, что в их присутствии совпадение с регулярным выражением возможно, только если совпадение будет найдено в начале строки (^) или в ее конце ($).
[[email protected] ~]$ grep -h '^zip' dirlist*.txt
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
[[email protected] ~]$ grep -h 'zip$' dirlist*.txt
gunzip
gzip
funzip
gpg-zip
preunzip
prezip
unzip
zip
[[email protected] ~]$ grep -h '^zip$' dirlist*.txt
zip
Здесь выполняется поиск в списке файлов строки zip, находящейся в начале строки, в конце строки и занимающей всю строку, от начала до конца. Обратите внимание, что регулярное выражение ^$ (начало и конец без каких-либо символов между ними) будет соответствовать пустым строкам.
в помощь любителям кроссвордов
Моя супруга обожает разгадывать кроссворды и иногда просит меня помочь с ответом на какой-нибудь вопрос. Например: «Слово из пяти букв, третья j, последняя r, которое означает...» Подобные вопросы навели меня на размышления.
Знаете ли вы, что в вашей системе Linux имеется словарь? Загляните в каталог /usr/share/dict, и вы обнаружите там один или несколько словарей. Файлы словарей, находящиеся в каталоге, — это обычные длинные списки слов, по одному в строке, упорядоченные по алфавиту. В моей системе файл words содержит больше 98 500 слов. Найти возможные ответы на вопрос в кроссворде можно с помощью следующей команды:
[[email protected] ~]$ grep -i '^..j.r$' /usr/share/dict/words
Major
major
Это регулярное выражение помогает найти в файле словаря все слова, длиной в пять букв, где третья буква — j и последняя — r.
Выражения в квадратных скобках и классы символов
В дополнение к возможности описать в регулярном выражении совпадение с любым символом в заданной позиции с помощью выражения в квадратных скобках можно также описать совпадение с одним символом из определенного множества. Выражение в квадратных скобках помогает определить множество символов (включая символы, которые иначе интерпретировались бы как метасимволы), которые находятся в данной позиции. В следующем примере используется множество из двух символов, благодаря которому обнаруживаются соответствия с последовательностями bzip и gzip:
[[email protected] ~]$ grep -h '[bg]zip' dirlist*.txt
bzip2
bzip2recover
gzip
Множество может содержать любое число символов. Метасимволы, заключенные в квадратные скобки, теряют свое специальное значение. Лишь два метасимвола интерпретируются особым образом, но при этом они имеют иной смысл. Первый — символ крышки (^), который используется для обозначения отрицания; второй — дефис (-), который используется для обозначения диапазона символов.
Отрицание
Если сразу после открывающей квадратной скобки стоит символ крышки (^), остальные символы множества интерпретируются как недопустимые в данной позиции. Проверим это, изменив предыдущий пример:
[[email protected] ~]$ grep -h '[^bg]zip' dirlist*.txt
bunzip2
gunzip
funzip
gpg-zip
preunzip
prezip
prezip-bin
unzip
unzipsfx
Включив отрицание, мы получили список файлов, имена которых содержат последовательность zip, которой предшествует любой символ, кроме b или g. Обратите внимание, что файл zip не был найден. Символ отрицания не отменяет необходимости присутствия символа в заданной позиции, он лишь требует, чтобы символ в этой позиции не принадлежал указанному множеству.
Символ крышки обозначает операцию отрицания, только если является первым символом в выражении в квадратных скобках; в противном случае он теряет свое специальное значение и превращается в обычный символ.
Традиционные диапазоны символов
Если необходимо сконструировать регулярное выражение, которое находило бы в наших списках все файлы с именами, начинающимися с заглавной буквы, это можно выполнить следующим образом:
[[email protected] ~]$ grep -h '^[ABCDEFGHIJKLMNOPQRSTUVWXZY]' dirlist*.txt
Достаточно просто поместить 26 букв в верхнем регистре в выражение в квадратных скобках. Но необходимость ввода всех этих символов вызывает некоторое беспокойство, поэтому предусмотрен другой способ:
[[email protected] ~]$ grep -h '^[A-Z]' dirlist*.txt