Регулярные выражения и команда grep
Оглавление
1. Как используются регулярные выражения
2. Что такое регулярные выражения?
7. Выражения в квадратных скобках и Классы символов
7.2 Традиционные диапазоны символов
8. Базовые (Basic) и Расширенные (Extended) регулярные выражения
10.1 ? – совпадение элемента ноль или один раз
10.2 * - совпадение элемента ноль или более раз
10.3 + - совпадение элемента один или более раз
10.4 { } - совпадение элемента указанное количество раз
Предыстория и источник: не все, кому приходится использовать регулярные выражения, до конца понимают, как они работают и как их создавать. Я тоже относился к этой группе – искал примеры регулярных выражений, подходящих под мои задачи, пытался их подправить по мере необходимости. Для меня всё в корне изменилось после прочтения книги The Linux Command Line (Second Internet Edition) автора William E. Shotts, Jr. В ней принципы работы регулярных выражений изложены настолько ясно, что после прочтения я научился их понимать, создавать регулярные выражения любой сложности и теперь использую их при каждой необходимости. Данный материал представляет собой перевод части главы, посвящённой регулярным выражениям. Этот материал предназначен для абсолютных новичков, которые совершенно не понимают, как работают регулярные выражения, но имеют некоторые представления о работе командной строки Linux. Надеюсь, эта статья поможет вам сделать такой же прорыв, который помогла мне. Если изложенный здесь материал не содержит ничего нового для вас, попробуйте посмотреть статью «Регулярные выражения и команда grep», в ней более подробно описываются опции grep, а также имеются дополнительные примеры.
Как используются регулярные выражения
Текстовые данные играют важную роль во всех Unix-подобных системах, таких как Linux. Среди прочего, текстом является и вывод консольных программ, и файлы конфигурации, отчётов и т.д. Регулярные выражения являются (пожалуй) одной из самых сложных концепций по работе с текстом, поскольку предполагают высокий уровень абстракции. Но время, потраченное на их изучение, с лихвой окупится. Умея использовать регулярные выражения, вы сможете делать удивительные вещи, хотя их полная ценность может быть не сразу очевидной.
В этой статье будет рассмотрено использование регулярных выражений вместе с командой grep. Но их применение не ограничивается только этим: регулярные выражения поддерживаются другими командами Linux, многими языками программирования, применяются при конфигурации (например, в настройках правил mod_rewrite в Apache), а также некоторые программы с графическим интерфейсом позволяют устанавливать правила для поиска/копирования/удаления с поддержкой регулярных выражений. Даже в популярной офисной программе Microsoft Word для поиска и замены текста вы можете использовать регулярные выражения и подстановочные символы.
Что такое регулярные выражения?
Говоря простым языком, регулярное выражение – это условное обозначение, символическая запись шаблона, который ищется в тексте. Регулярные выражения поддерживаются многими инструментами командной строки и большинством языков программирования и применяются для облегчения решения проблем с текстовыми манипуляциями. Однако (будто мало нам их сложности), не все регулярные выражения одинаковы. Они немного меняются от инструмента к инструменту и от языка программирования до языка. Для нашего обсуждения мы ограничимся регулярными выражениями, описанными в стандарте POSIX (который будет охватывать большинство инструментов командной строки), в отличие от многих языков программирования (в первую очередь Perl), которые используют несколько более крупные и более богатые наборы нотаций.
grep
Основной программой, которую мы будем использовать для регулярных выражений, является наш старый приятель, grep. Имя «grep» на самом деле происходит от фразы «global regular expression print», поэтому мы можем видеть, что grep имеет какое-то отношение к регулярным выражениям. По сути, grep ищет в текстовых файлах текст, который подходит под указанное регулярное выражение и выводит в стандартный вывод любую строку, содержащую соответствие.
grep может делать поиск по тексту, получаемому в стандартном вводе, например:
ls /usr/bin | grep zip
Эта команда выведет список файлов в директории /usr/bin, чьи имена содержат подстроку «zip».
Программа grep может искать по тексту в файлах.
Общий синтаксис использования:
grep [опции] regex [файл...]
Где:
- regex – это регулярное выражение.
- [файл…] – один или несколько файлов, в которых будет проводиться поиск по регулярному выражению.
[опции] и [файл…] могут отсутствовать.
Список самых часто используемых опций grep:
Опция | Описание |
---|---|
-i | Игнорировать регистр. Не делать различия между большими и маленькими символами. Также можно задать опцией --ignore-case. |
-v | Инвертировать соответствие. Обычно grep печатает строки, которые содержат соответствие. Эта опция приводит к тому, что grep выводит каждую строку, которая не содержит соответствия. Также можно использовать --invert-match. |
-c | Печатать количество соответствий (или несоответствий, если указана опция -v) вместо самих строк. Можно также указывать опцией --count. |
-l | Вместо самих строк печатать имя каждого файла, который содержит соответствие. Можно указать опцией --files-with-matches. |
-L | Как опция -l, но печатает только имена файлов, которые не содержат совпадений. Другое имя опции --files-withoutmatch. |
-n | Добавление к началу каждой совпавшей строке номера строчки внутри файла. Другое имя опции --line-number. |
-h | Для поиска по нескольким файлам, подавлять вывод имени файла. Также можно указать опцией --no-filename. |
Чтобы полнее исследовать grep, давайте создадим несколько текстовых файлов для поиска:
ls /bin > dirlist-bin.txt ls /usr/bin > dirlist-usr-bin.txt ls /sbin > dirlist-sbin.txt ls /usr/sbin > dirlist-usr-sbin.txt ls dirlist*.txt dirlist-bin.txt dirlist-sbin.txt dirlist-usr-bin.txt dirlist-usr-sbin.txt
Мы можем выполнить простой поиск по нашему списку файлов следующим образом:
grep bzip dirlist*.txt dirlist-bin.txt:bzip2 dirlist-bin.txt:bzip2recover
В этом примере grep ищет по всем перечисленным файлам строку bzip и находит два соответствия, оба в файле dirlist-bin.txt. Если нас интересует только список файлов, содержащих соответствия, а не сами подходящие строки, мы можем указать опцию -l:
grep -l bzip dirlist*.txt dirlist-bin.txt
И наоборот, если бы мы хотели увидеть только список файлов, которые не содержали совпадений, мы могли бы сделать это:
grep -L bzip dirlist*.txt dirlist-sbin.txt dirlist-usr-bin.txt dirlist-usr-sbin.txt
Если вывод отсутствует – значит файлы, удовлетворяющие условиям не найдены.
Метасимволы и литералы
Хотя это может показаться неочевидным, наши поиски с grep всегда используют регулярные выражения, хоть и очень простые. Регулярное выражение «bzip» означает, что совпадение будет происходить (т.е. строка будет считаться подходящей) только в том случае, если строка в файле содержит не менее четырех символов и что где-то в строке символы «b», «z», «i» и «p» находятся в этом порядке, без других символов между ними. Символы в строке «bzip» являются литералами, т.е. буквальными символами, поскольку они соответствуют самим себе. В дополнение к литералам регулярные выражения могут также включать метасимволы, которые используются для задания более сложных совпадений. Метасимволы регулярного выражения состоят из следующих:
^ $ . [ ] { } - ? * + ( ) | \
Все остальные символы считаются литералами. Символ обратной косой черты может иметь различные значения. Он используется в нескольких случаях для создания мета-последовательностей, а также позволяет метасимволам быть экранированными и рассматриваться не как метасимволы, а как литералы.
Примечание: как мы можем видеть, многие метасимволы регулярного выражения также являются символами, имеющими значение для оболочки (выполнение раскрытия). При указании регулярного выражения, содержащего метасимволы командной строки, крайне важно, чтобы оно было заключено в кавычки, в противном случае шелл будет интерпретировать их по-своему и сломает вашу команду.
Любой символ
Первый метасимвол, с которого мы начнём знакомство, это символ точки, который означает «любой символ». Если мы включим его в регулярное выражение, то он будет соответствовать любому символу для этой позиции символа. Пример:
grep -h '.zip' dirlist*.txt bunzip2 bzip2 bzip2recover gunzip gzip funzip gpg-zip mzip p7zip preunzip prezip prezip-bin unzip unzipsfx
Мы искали любую строку в наших файлах, которая соответствует регулярному выражению «.zip». Нужно отметить парочку интересных моментов в полученных результатах. Обратите внимание, что программа zip не была найдена. Это от того, что включение метасимвола точка в наше регулярное выражение увеличило длину, требуемую для совпадения, до четырёх символов, а поскольку имя «zip» содержит только три, то оно не соответствует. Также если какие-либо файлы из наших списков содержали расширение файла .zip, они также считались бы подходящими, поскольку символ точки в расширении файла, также подходит под условие «любой символ».
Анкоры
Символ каретки (^) и знак доллара ($) считаются в регулярных выражениях анкорами. Это означает, что они вызывают совпадение, только если регулярное выражение найдено в начале строки (^) или в конце строки ($):
grep -h '^zip' dirlist*.txt zip zipcloak zipdetails zipgrep zipinfo zipnote zipsplit
grep -h 'zip$' dirlist*.txt gunzip gzip funzip gpg-zip mzip p7zip preunzip prezip unzip zip
grep -h '^zip$' dirlist*.txt zip
Здесь мы искали по спискам файлов строку «zip», расположенную в начале строки, в конце строки, а также в строке, где она была бы одновременно и в начале, и в конце (т.е. вся строка содержала бы только «zip»). Обратите внимание, что регулярное выражение «^$» (начало и конец между которыми ничего нет) будет соответствовать пустым строкам.
Небольшое лирическое отступление: помощник по разгадыванию кроссвордов
Даже с нашими ограниченными на данный момент познаниями в регулярных выражениях мы можем делать что-то полезное.
Если вы когда-нибудь разгадывали кроссворды, то вам нужно было решать задачи вроде «что за слово из пяти букв, где третья буква «j», а последняя буква «r», которое означает…». Этот вопрос может заставить задуматься. Знаете ли вы, что в системе Linux есть словарь? А он есть. Загляните в директорию /usr/share/dict, там вы можете найти один или несколько словарей. Словари, размещённые там, это просто длинные списки слов по одному на строку, расположенные в алфавитном порядке. В моей системе файл словаря содержит 99171 слов. Для поиска возможных ответов на вышеприведённый вопрос кроссворда, мы можем сделать так:
grep -i '^..j.r$' /usr/share/dict/american-english Major major
Используя это регулярное выражение, мы можем найти все слова в нашем файле словаря, которое имеет длину в пять букв, имеет «j» в третьей позиции и «r» в последней позиции.
В примере использовался английский файл словаря, поскольку он присутствует в системе по умолчанию. Предварительно скачав соответствующий словарь, вы можете делать аналогичные поиски по словам на кириллице или из любых других символов.
Выражения в квадратных скобках и Классы символов
В дополнение к совпадению любого символа в заданной позиции в нашем регулярном выражении, мы также, используя выражения в квадратных скобках, можем задать совпадение единичного символа из указанного набора символов. С выражениями в квадратных скобках мы можем указать набор символов для соответствия (включая символы, которые в противном случае были бы истолкованы как метасимволы). В этом примере, используя набор из двух символов:
grep -h '[bg]zip' dirlist*.txt bzip2 bzip2recover gzip
мы найдём любые строчки, содержащие строки «bzip» или «gzip».
Набор может содержать любое количество символов, а метасимволы теряют своё специальное значение, когда помещаются внутрь квадратных скобок. Тем не менее, есть два случая в которых метасимволы, используемые внутри квадратных скобок, имеют различные значения. Первый – это каретка (^), которая используется для указания отрицания; второй – это тире (-), которое используется для указания диапазона символов.
Отрицание
Если первым символом выражения в квадратных скобках является каретка (^), то остальные символы принимаются как набор символов, которые не должны присутствовать в заданной позиции символа. Сделаем это изменив наш предыдущий пример:
grep -h '[^bg]zip' dirlist*.txt bunzip2 gunzip funzip gpg-zip mzip p7zip preunzip prezip prezip-bin unzip unzipsfx
С активированным отрицанием, мы получили список файлов, которые содержат строку «zip», перед которой идёт любой символ, кроме «b» или «g». Обратите внимание, что zip не был найден. Отрицаемый набор символов всё равно требует символ на заданной позиции, но символ не должен быть членом инвертированного набора.
Символ каретки вызывает отрицание только если он является первым символом внутри выражения в квадратных скобках; в противном случае, он теряет своё специальное назначение и становится обычным символом из набора.
Традиционные диапазоны символов
Если мы хотим сконструировать регулярное выражение, которое должно найти каждый файл из нашего списка, начинающийся на заглавную букву, мы можем сделать следующее:
grep -h '^[ABCDEFGHIJKLMNOPQRSTUVWXZY]' dirlist*.txt MAKEDEV GET HEAD POST VBoxClient X X11 Xorg ModemManager NetworkManager VBoxControl VBoxService
Суть в том, что мы разместили все 26 заглавных букв в выражение внутри квадратных скобок. Но мысль печатать их все не вызывает энтузиазма, поэтому есть другой путь:
grep -h '^[A-Z]' dirlist*.txt
Используя трёхсимвольный диапазон, мы можем сократить запись из 26 букв. Таким способом можно выразить любой диапазон символов, включая сразу несколько диапазонов, такие, как это выражение, которое соответствует всем именам файлов, начинающихся с букв и цифр:
grep -h '^[A-Za-z0-9]' dirlist*.txt
В диапазонах символов мы видим, что символ чёрточки трактуется особым образом, поэтому как мы можем включить символ тире в выражение внутри квадратных скобок? Сделав его первым символом в выражении. Рассмотрим два примера:
grep -h '[A-Z]' dirlist*.txt
Это будет соответствовать каждому имени файла, содержащему заглавную букву. При этом:
grep -h '[-AZ]' dirlist*.txt
будет соответствовать каждому имени файла, содержащему тире, или заглавную «A», или заглавную «Z».
Классы символов POSIX
Подробнее о POSIX вы можете почитать в Википедии.
В POSIX имеются свои классы символов, которые вы можете использовать в регулярных выражениях:
Класс символов | Описание |
---|---|
[:alnum:] | Алфавитно-цифровые символы. В ASCII эквивалентно: [A-Za-z0-9] |
[:word:] | То же самое, что и [:alnum:], с дополнительным символом подчёркивания (_). |
[:alpha:] | Алфавитные символы. В ASCII эквивалентно: [A-Za-z] |
[:blank:] | Включает символы пробела и табуляции. |
[:cntrl:] | Управляющие коды ASCII. Включает ASCII символы с 0 до 31 и 127. |
[:digit:] | Цифры от нуля до девяти. |
[:graph:] | Видимые символы. В ASCII сюда включены символы с 33 по 126. |
[:lower:] | Буквы в нижнем регистре. |
[:punct:] | Символы пунктуации. В ASCII эквивалентно: [-!»#$%&'()*+,./:;<=>?@[\\\]_`{|}~] |
[:print:] | Печатные символы. Все символы в [:graph:] плюс символ пробела. |
[:space:] | Символы белых пробелов, включающих пробел, табуляцию, возврат каретки, новую строку, вертикальную табуляцию и разрыв страницы. В ASCII эквивалентно: [ \t\r\n\v\f] |
[:upper:] | Символы в верхнем регистре. |
[:xdigit:] | Символы, используемые для выражения шестнадцатеричных чисел. В ASCII эквивалетно: [0-9A-Fa-f] |
В этих выражениях квадратные скобки и двоеточия являются частью записи класса символов (диапазонов).
Внимание: в зависимости от настроек локали, [:alnum:], [:word:], [:alpha:] и другие буквенные диапазоны могут включать буквы вашего алфавита, например, русского. Т.е. [:alpha:] может соответствовать не [A-Za-z], а [A-Za-zА-Яа-я].
Базовые (Basic) и расширенные (Extended) регулярные выражения
Имеется два вида регулярных выражений: базовые регулярные выражения (basic regular expressions (BRE)) и расширенные регулярные выражения (extended regular expressions (ERE)). Рассмотренные нами возможности поддерживаются любыми приложениями, совместимыми с POSIX и имеющими реализацию BRE. Одной из таких программ является наша grep.
В чём различия BRE и ERE? Всё дело в метасимволах. В BRE распознаются следующие метасимволы:
^ $ . [ ] *
Все другие символы расцениваются как литералы. В ERE добавлены следующие метасимволы (и связанные с ними функции):
( ) { } ? + |
Тем не менее (и это смешная часть), символы «(», «)», «{» и «}» в BRE обрабатываются как метасимволы, если они экранированы обратным слешем; в то время как в ERE постановка перед любыми метасимволами обратного слеша приводит к тому, что они трактуются как литералы.
Поскольку функции, которые мы далее собираемся рассмотреть, являются частью ERE (расширенных регулярных выражений), нам понадобиться использовать другую grep. Традиционно это выполнялось программой egrep, но сейчас она не рекомендуется к использованию, вместо неё следует использовать GNU версию grep, которая также поддерживает расширенные регулярные выражения при использовании опции -E.
Альтернативы
Первой функцией расширенных регулярных выражений, которую мы обсудим, называется альтернативы, которая является возможностью, позволяющей искать соответствующие вхождения из набора выражений. Как выражения в квадратных скобках позволяют единичному символу соответствовать из указанного набора символов, альтернативы позволяют соответствия из набора строк или других регулярных выражений.
Для демонстрации мы будем использовать grep в паре с echo. Для начала давайте попробуем проверить простое старое соответствие строки:
echo "AAA" | grep AAA AAA echo "BBB" | grep AAA
Весьма простой пример, в котором мы передавали по трубе вывод от echo в grep и смотрели на результат. Когда случалось совпадение, то оно печаталось в стандартный вывод; когда совпадений не встречается, то не выводится никакой результат.
Сейчас мы добавим альтернативы, выраженные с помощью метасимвола вертикальная черта:
echo "AAA" | grep -E 'AAA|BBB' AAA echo "BBB" | grep -E 'AAA|BBB' BBB echo "CCC" | grep -E 'AAA|BBB'
Здесь мы видим регулярное выражение 'AAA|BBB', которое означает «соответствие или строке AAA или строке BBB». Обратите внимание, что поскольку это расширенная функция, мы добавили к grep опцию -E (хотя вместо этого можно было использовать просто программу egrep, но это не рекомендуется – команда egrep теперь является устаревшей). Ещё мы заключили регулярное выражение в кавычки, для предотвращения интерпретации Башем вертикальной черты в качестве оператора pipe (труба). Альтернативы не ограничены двумя вариантами выбора:
echo "AAA" | grep -E 'AAA|BBB|CCC' AAA
Для комбинирования альтернатив с другими элементами регулярных выражений, мы можем использовать () для разделения альтернатив:
grep -Eh '^(bz|gz|zip)' dirlist*.txt
Это выражение будет соответствовать именам файлов в нашем списке, которые начинаются либо с «bz», «gz» или «zip». Если мы уберём скобки из нашего регулярного выражения:
grep -Eh '^bz|gz|zip' dirlist*.txt
то его значение измениться, теперь оно будет соответствовать любому имени файла, начинающемуся с «bz» или содержащему «gz» или содержащему «zip».
Кванторы
Расширенные регулярные выражения поддерживают несколько способов указания количества раз, которое совпадает элемент.
? – совпадение элемента ноль или один раз
Этот квантор по сути сводится к «сделать предыдущий элемент опциональным». Допустим, мы хотим проверить телефонный номер на правильность, и мы считаем телефонный номер правильным, если он соответствует одной из этих двух форм:
(nnn) nnn-nnnn nnn nnn-nnnn
- где «n» - это число. Мы можем сконструировать регулярное выражение вроде такого:
^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$
В этом выражении мы поставили за символами скобок знаки вопроса, чтобы указать, что они должны встречаться ноль или один раз. Опять, поскольку круглые скобки являются обычно метасимволами (в ERE), перед ними мы поставили обратные слеши, благодаря которым они стали обрабатываться как литералы.
Давайте попробуем это:
echo "(555) 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$' (555) 123-4567 echo "555 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$' 555 123-4567 echo "AAA 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
Здесь мы видим, что выражение соответствует обоим формам телефонного номера, но не соответствует одному, содержащему не-цифровые символы.
* - совпадение элемента ноль или более раз
Как и метасимвол ?, * используется для обозначения опционального элемента; тем не менее, в отличие от ?, элемент может встречаться любое количество раз, не только одиножды. Допустим мы хотим увидеть, является ли строка предложением; это так, если она начинается с заглавной буквы, затем содержит любое количество больших и маленьких букв, пробелов и заканчивается точкой. Для соответствия этому (очень приблизительному) определению предложения, вы должны использовать регулярное выражение вроде такого:
[[:upper:]][[:upper:][:lower:] ]*\.
Выражение состоит из трёх пунктов: выражение в квадратных скобках содержащее класс символов [:upper:], выражение в квадратных скобках, содержащее оба класса символов [:upper:] и [:lower:] и пробел, в конце идёт точка, экранированная обратным слешем. Второй элемент заканчивается метасимволом *, благодаря которому после начальной заглавной буквы в нашем предложении за ней могут следовать любое количество заглавных и строчных букв и пробелов, и оно всё равно считается подходящим:
echo "This works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.' This works. echo "This Works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.' This Works. echo "this does not" | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
Выражение соответствует первым двум проверкам, но не третьей, поскольку в ней отсутствует символ требуемой начальной заглавной буквы и конечная точка.
+ - совпадение элемента один или более раз
Метасимвол + работает очень похоже на *, кроме того, что он требует хотя бы один экземпляр предшествующего элемента, чтобы привести к совпадению. Это регулярное выражение будет соответствовать только строчкам, состоящих из групп из одного или более алфавитных символов, разделённых одним пробелом:
^([[:alpha:]]+ ?)+$
echo "This that" | grep -E '^([[:alpha:]]+ ?)+$' This that echo "a b c" | grep -E '^([[:alpha:]]+ ?)+$' a b c echo "a b 9" | grep -E '^([[:alpha:]]+ ?)+$' echo "abc d" | grep -E '^([[:alpha:]]+ ?)+$'
Мы видим, что это выражение не соответствует строке "a b 9", поскольку она содержит неалфавитный символ; и не соответствует "abc d", поскольку символы «c» и «d» разделены более чем одним символом пробела.
{ } - совпадение элемента указанное количество раз
Метасимволы { и } используются для выражения минимального и максимального числа требуемых соответствий. Они могут задаваться четырьмя различными способами:
Спецификатор | Значение |
---|---|
{n} | Соответствие предыдущего элемента, если он встречается ровно n раз. |
{n,m} | Соответствие предыдущего элемента, если он встречается по меньшей мере n раз, но не более чем m раз. |
{n,} | Соответствие предыдущего элемента, если он встречается n или более раз. |
{,m} | Соответствие предыдущего элемента, если он встречается не более чем m раз. |
Возвращаясь к нашему раннему примеру с телефонными номерами, мы можем использовать этот метод указания повторений для упрощения оригинального регулярного выражения с:
^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$
до:
^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$
Давайте испытаем его:
echo "(555) 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$' (555) 123-4567 echo "555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$' 555 123-4567 echo "5555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
Как мы можем видеть, наше улучшенное регулярное выражение может успешно проверять правильность телефонных номеров как со скобками, так и без скобок, и при этом отбрасывает номера, которые имеют неправильный формат.
Заключение
Если вы успешно освоили материал из этой статьи, то вас также может заинтересовать статья «Команда grep: опции, регулярные выражения и примеры использования», в которой более подробно рассматриваются все опции команды grep, там вы сможете найти что-то новое о регулярных выражениях (например, об обратных отсылках), а также познакомитесь с несколькими дополнительными примерами регулярных выражений.
Также смотрите практические примеры поиска и применения опций в статьях:
- Как найти все файлы, содержащие определённый текст
- Как использовать кавычки в регулярных выражениях grep
- Как обработать каждую строку, полученную от команды grep
Оригинал статьи: https://hackware.ru/?p=3238