Главная » Программирование для UNIX » Семейство программ grep

0

Программа grep была  упомянута в главе 1 и с тех пор неоднократно использовалась в примерах.

$ grep  шаблон имена5файлов …

просматривает указанные файлы либо  стандартный ввод  и  выводит все строки, содержащие образец. Программа незаменима при  поиске переменных в программах, слов в документах или в выходных данных какой-либо программы.

$ grep  –n variable *.[ch]        Найти variable в программах на Си

$ grep  From  $MAIL                             Напечатать заголовки почтовых сообщений

$ grep  From  $MAIL  | grep  –v mary            Заголовки сообщений,

не принадлежащих  mary

$ grep  –y mary  $HOME/lib/phone-book        Найти телефонный номер   mary

$ who  | grep  mary                        Зарегистрировалась ли mary  в системе?

$ ls | grep  –v temp                     Имена файлов, не содержащие temp

Параметр –n выводит номера строк, –v изменяет условие на противоположное, а –y устанавливает соответствие символов нижнего регистра в образце символам обоих регистров в файле (символы верхнего регистра по-прежнему соответствуют только верхнему регистру).

До сих  пор во всех  примерах программа grep выполняла поиск обычных  строк, состоящих из букв  и цифр. Но в действительности она может  находить и более сложные образцы: grep может интерпретировать выражения на простом языке описания строк.

С технической точки зрения шаблоны являются ограниченным вари антом описателей строк, известных как регулярные выражения. Программа grep интерпретирует те же  регулярные выражения, что  и редактор ed; фактически она была  создана из него  (всего  за один  вечер) путем  «хирургического вмешательства».

Регулярные выражения образуются присваиванием специальных зна чений определенным символам, таким, например, как *, которые ис-

пользуются  оболочкой.  Существует  еще   несколько  метасимволов, имеющих, к сожалению, разночтения в применении. Рассмотрим их вкратце (список всех метасимволов, используемых в регулярных выражениях, приведен в табл. 4.1).

Таблица 4.1. Регулярные выражения grep и egrep (в порядке понижения приоритета)

Метасимволы

Значение

c

\c

^

$

.

[…]

[^…]

\n r* r+ r?

r1r2  r1|r2

\(r\) (r)

любой не специальный символ c совпадает сам с собой отключает все специальные значения символа c начало строки

конец строки

произвольный одиночный символ

любой  из символов множества …; допустимы диапазоны, например a–z

любой символ, не входящий в …; допустимы диапазоны то же, что в n-м фрагменте  \(…\) (только grep)

ноль или больше вхождений r

одно или больше вхождений r (только egrep) ноль или одно вхождение r (только egrep)

r2 следует за r1

r1 или r2 (только egrep)

регулярное  выражение  r с тегами  (только grep); может  быть  вложенным

регулярное выражение r (только egrep); может быть вложенным не   существует   регулярного   выражения,   соответствующего

символу новой строки

Метасимволы ^ и $ «привязывают» шаблон к началу или концу строки соответственно. Например, выражение

$ grep  From  $MAIL

находит в сообщениях строки, содержащие образец From, а

$ grep  ’^From’ $MAIL

выберет только те строки, которые начинаются с From, а значит, скорее всего, находятся  в  заголовке  сообщения. Метасимволы  регулярных выражений перекрываются  метасимволами оболочки, поэтому пара метр команды grep рекомендуется заключать в одинарные кавычки.

Программа grep,  как и  оболочка,  поддерживает  «классы символов», так что [a–z] соответствует любой  букве  нижнего регистра. Но есть  и

отличия: если класс символов начинается со знака ^, то шаблону соответствуют все символы, кроме  принадлежащих классу. Следовательно, выражению  [^0–9]  соответствуют все  символы, не  являющиеся цифрами. Кроме того, в оболочке символ \ перед символами ] и – озна чает, что они входят в класс, тогда  как программы grep и ed требуют, чтобы  эти  символы использовались там, где  исключена двусмысленность. Например, последовательность [][–] (это важно!) соответствует открывающей и закрывающей квадратным скобкам и знаку минус.

Знак . (точка) эквивалентен вопросительному знаку в оболочке, он соответствует любому  символу. (Пожалуй, точка –  это  знак,  имеющий больше всего  различных значений в разных программах для UNIX.) Вот пара примеров:

$ ls –l  | grep  ’^d’                    Список подкаталогов

$ ls –l  | grep  ’^…….rw’        Файлы, доступные остальным для чтения и записи

Знак ^ и следующие за ним  семь точек соответствуют семи  произвольным символам в начале строки; в случае применения к выходному потоку команда ls  –l задает строку прав  доступа.

Оператор замыкания (closure) * действует на предыдущий символ либо метасимвол  (включая  и  класс  символов) в  выражении, такая  конструкция соответствует произвольному числу следующих друг за другом символов, заданных в образце. Например, x* определяет последовательность символов x максимально возможной длины, [a–zA–Z]* определяет  строку  из  букв, .* соответствует строке любых  символов, а

.*x  – строке произвольных символов, заканчивающейся символом x, включая этот последний символ.

Отметим две важные особенности замыкания. Во-первых, оператор замыкания действует только на один  символ, так что xy* соответствует нескольким символам y, следующим за символом x, а не строке вида xyxyxy. Во-вторых, «произвольное количество» включает ноль, поэтому,  если  необходим хотя бы один  символ, надо  указывать его отдельно.  Например, правильное выражение для  определения  буквенной строки выглядит  так:  [a–zA–Z][a–zA–Z]* (буква и  следующие  за  ней ноль или более букв). Шаблонный символ * для имени файла в оболоч ке – это то же, что и регулярное выражение .*.

В grep нет регулярного выражения, которое соответствовало бы симво лу новой строки, каждая строка обрабатывается отдельно.

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

$ grep  ’^[^:]*::’ /etc/passwd

Это  означает:  начало  строки,  произвольное  количество  «недвоеточий», два двоеточия.

Программа grep  – старейший член  семейства, в котором позже появились  fgrep и egrep. Сущность их работы одинакова, за исключением того, что fgrep  выполняет поиск одновременно нескольких строк, a egrep интерпретирует истинные регулярные выражения так же, как grep, но с использованием оператора ИЛИ  и скобок, позволяющих группировать выражения, как это описано ниже.

Обе команды позволяют при  помощи параметра –f указать файл, содержащий  шаблон. В файле могут  находиться несколько  шаблонов, каждый на отдельной строке, поиск по которым выполняется параллельно. Например, если вы часто делаете ошибки в одних и тех же словах, то можете сохранить их в файле, по одному  в каждой строке, и с помощью fgrep проверять их наличие в своих документах:

$ fgrep  –f  common-errors document

Команда egrep обрабатывает те же  регулярные выражения, что и grep (см.  табл. 4.1), но  с  несколькими  дополнениями. Скобки  позволяют группировать выражения, так  что (xy)* определяет пустую строку, xy, xyxy, xyxyxy и т. д. Оператор или  записывается как вертикальная черта

|; выражение today|tomorrow означает today либо tomorrow  – так  же, как и выражение to(day|morrow). И наконец, в egrep имеются два дополнительных оператора замыкания,   + и ?. Шаблон x+ определяет один или  больше символов x, а x? – ноль или один символ, но не больше.

Программа egrep хорошо подходит для поиска слов с заданными свойст вами  в словаре. Мы работаем со словарем Webster’s Second International, который хранится в системе в  виде  списка слов,  по одному  на строку, без словарных статей. Вы можете использовать словарь /usr/  dict/words. Он не так  велик и предназначен для проверки орфографии; проверьте, в каком формате хранятся в нем слова. Приведем шаблон для поиска слов, содержащих все гласные в алфавитном порядке:

$ cat  alphvowels

^[^aeiou]*a[^aeiou]*e[^aeiou]*i[^aeiou]*o[^aeiou]*u[^aeiou]*$

$ egrep  –f  alphvowels  /usr/dict/web2 | 3

abstemious

abstemiously

abstentious

achelious

acheirous

acleistous

affectious

annelidous

arsenious

arterious

bacterious

caesious

facetious

facetiously

fracedinous

majestious

$

Шаблон в файле  alphvowels не заключается в  кавычки. Если  шаблон egrep находится в кавычках, то оболочка не интерпретирует его сама, а лишь убирает кавычки, поэтому egrep никогда их не видит. Но так как файл оболочкой не обрабатывается, то и кавычки в нем не требуются.

В вышеприведенном примере можно было использовать команду grep, но egrep выполняет поиск по шаблонам с замыканиями намного быстрее, особенно  в больших файлах.

Вот еще один  пример – поиск слов,  состоящих из шести и более букв, расположенных в алфавитном порядке:

$ cat  monotonic

^a?b?c?d?e?f?g?h?i?j?k?l?m?n?o?p?q?r?s?t?u?v?w?x?y?z?$

$ egrep  –f  monotonic  /usr/dict/web2  | grep  ’……’  |  5

abdest

acknow

adipsy

agnosy

almost

befist

behint

beknow

bijoux

biopsy

chintz

dehors

dehort

deinos

dimpsy

egilops

ghosty

$

(Egilops – это болезнь пшеницы.)1  Обратите внимание на использование grep для фильтрации вывода egrep.

Зачем нужны три программы grep? Дело в том, что fgrep, хоть и не умеет обрабатывать метасимволы, зато  эффективно выполняет поиск нескольких тысяч слов  одновременно (после  инициализации время выполнения не зависит от количества слов),  и вследствие этого применяется главным образом в таких задачах, как библиографический поиск. Обычно размер шаблона fgrep намного превосходит возможности алго ритмов, реализованных  в  grep  и  egrep.  Сложнее объяснить  разницу между grep и egrep. Программа grep появилась намного раньше остальных, она поддерживает синтаксис регулярных выражений, знакомый по редактору ed, обрабатывает регулярные выражения с тегами и имеет большой набор параметров. Программа egrep обрабатывает больше различных выражений (за исключением тегов)  и выполняется намного  быстрее  (причем  скорость не  зависит от  вида  шаблона),  но  стан дартная версия дольше стартует на сложных выражениях. Существует более  новая версия, которая стартует быстрее, так  что egrep и grep могут  быть объединены в одну программу поиска по шаблону.

Упражнение 4.1.  Изучите регулярные выражения с тегами (\(  и \)) в приложении 1 или в ed(1) и используйте grep для поиска палиндромов – слов,   пишущихся  одинаково в  обоих  направлениях. Подсказка: задайте отдельные шаблоны для каждой длины слова. ~

Упражнение 4.2. Схема  работы grep заключается в чтении одной  строки, проверке совпадений и повторении цикла. Как  может отразиться на grep возможность задания в шаблоне символа новой строки? ~

1        Трудно понять, почему авторы сочли  уместным пояснить значение именно этого слова. Расширим комментарий: abdest – (у мусульман) ритуал омовения рук  перед  молитвой; dehors – снаружи, за пределами; (to) dehort – отговаривать, разубеждать; dimpsy – тусклый, сумеречный. – Примеч. ред.

Источник: Керниган Б., Пайк Р., UNIX. Программное окружение. – Пер. с англ. – СПб: Символ-Плюс, 2003. – 416 с., ил.

По теме:

  • Комментарии