Egrep примеры регулярных выражений. Пять примеров использования grep

В сегодняшней статье хочу коснуться такой огромной темы как Регулярные выражения . Думаю всем известно, что тема регексов (так регулярные выражения называются на сленге) - необъятна в объеме одного поста.

Начну с того, что существует несколько разновидностей регулярных выражений:

1. Традиционные регулярные выражения (они же основные, базовые и basic regular expressions (BRE))

  • синтаксис данных выражений определен, как устаревший, но тем не менее до сих пор широко распространен и используется многими утилитами UNIX
  • Основные регулярные выражения включают в себя следующие метасимволы (об их значениях ниже):
    • \{ \} — первоначальный вариант для { } (в расширенных)
    • \(\) — первоначальный вариант для () (в расширенных)
    • \n , где n — номер от 1 до 9
  • Особенности использования данных метасимволов:
    • Звёздочка должна следовать после выражения, соответствующего единичному символу. Пример: * .
    • Выражение \(блок \)* следует считать неправильным. В некоторых случаях оно соответствует нулю или более повторений строки блок . В других оно соответствует строке блок * .
    • Внутри символьного класса специальные значения символов, в основном, игнорируются. Особые случаи:
    • Чтобы добавить символ ^ в набор, его следует поместить туда не первым.
    • Чтобы добавить символ - в набор, его следует поместить туда первым или последним. Например:
      • шаблон DNS-имени, куда могут входить буквы, цифры, минус и точка-разделитель: [-0-9a-zA-Z.] ;
      • любой символ, кроме минуса и цифры: [^-0-9] .
    • Чтобы добавить символ [ или ] в набор, его следует поместить туда первым. Например:
      • соответствует ] , [ , a или b .

2. Расширенные регулярные выражения (они же extended regular expressions (ERE))

  • Синтаксис данных выражений аналогичен синтаксису основных выражений, за исключением:
    • Отменено использование обратной косой черты для метасимволов { } и () .
    • Обратная косая черта перед метасимволом отменяет его специальное значение.
    • Отвергнута теоретически нерегулярная конструкция \n .
    • Добавлены метасимволы + , ? , | .

3. Регулярные выражения, совместимые с Perl (они же Perl-compatible regular expressions (PCRE))

  • имеют более богатый и в то же время предсказуемый синтаксис, чем даже POSIX ERE, поэтому часто используется приложениями.

Регулярные выражения состоят из шаблонов, вернее сказать задают шаблон поиска. Шаблон состоит из правил поиска, которые составляются из символов и метасимволов .

Правила поиска определяются следующими операциями :

Перечисление |

Вертикальная черта (|) разделяет допустимые варианты, можно сказать - логическое ИЛИ. Например, «gray|grey» соответствует gray или grey .

Группировка или объединение ()

Круглые скобки используются для определения области действия и приоритета операторов. Например, «gray|grey» и «gr(a|e)y» являются разными образцами, но они оба описывают множество, содержащее gray и grey .

Квантификация {} ? * +

Квантификатор после символа или группы определяет, сколько раз предшествующее выражение может встречаться.

общее выражение, повторений может быть от m до n включительно .

общее выражение, m и более повторений .

общее выражение, не более n повторений .

ровно n повторений .

Знак вопроса означает 0 или 1 раз, то же самое, что и {0,1} . Например, «colou?r» соответствует и color , и colour .

Звёздочка означает 0, 1 или любое число раз ({0,} ). Например, «go*gle» соответствует ggle , gogle , google и др.

Плюс означает хотя бы 1 раз ({1,} ). Например, «go+gle» соответствует gogle , google и т. д. (но не ggle ).

Конкретный синтаксис данных регулярных выражений зависит от реализации. (то есть в базовых регулярных выражениях символы { и } - экранируются обратным слешем)

Метасимволы , говоря простым языком - это символы, которые не соответствуют своему реальному значению, то есть символ. (точка) - это не точка, а любой один символ, и т.п. прошу ознакомиться с метасимволами и их значениями:

. соответствует одному любому символу
[что-то] Соответствует любому единичному символу из числа заключённых в скобки. При этом:Символ «-» интерпретируется буквально только в том случае, если он расположен непосредственно после открывающей или перед закрывающей скобкой: или [-abc]. В противном случае, он обозначает интервал символов.Например, соответствует «a», «b» или «c». соответствует буквам нижнего регистра латинского алфавита. Эти обозначения могут и сочетаться: соответствует a, b, c, q, r, s, t, u, v, w, x, y, z.Чтобы установить соответствие символам «[» или «]», достаточно, чтобы закрывающая скобка была первым символом после открывающей: соответствует «]», «[», «a» или «b».Если значение в квадратных скобах предварено символом ^, то значение выражения соответствует единичному символу из числа тех, которых нет в скобках . Например, [^abc] соответствует любому символу, кроме «a», «b» или «c». [^a-z] соответствует любому символу, кроме символов нижнего регистра в латинском алфавите.
^ Соответствует началу текста (или началу любой строки, если режим построчный).
$ Соответствует концу текста (или концу любой строки, если режим построчный).
\(\) или () Объявляет «отмеченное подвыражение» (сгруппированное выражение), которое может быть использовано позже (см. следующий элемент: \n ). «Отмеченное подвыражение» также является «блоком». В отличие от других операторов, этот (в традиционном синтаксисе) требует бэкслеша, в расширенном и Perl символ \ - не нужен.
\n Где n — это цифра от 1 до 9; соответствует n -му отмеченному подвыражению (например (abcd)\0, то есть символы abcd отмечены нулем). Эта конструкция теоретически нерегулярна , она не была принята в расширенном синтаксисе регулярных выражений.
*
  • Звёздочка после выражения, соответствующего единичному символу, соответствует нулю или более копий этого (предшествующего) выражения. Например, «*» соответствует пустой строке, «x», «y», «zx», «zyx», и т. д.
  • \n *, где n — это цифра от 1 до 9, соответствует нулю или более вхождений для соответствия n -го отмеченного подвыражения. Например, «\(a.\)c\1*» соответствует «abcab» и «abcaba», но не «abcac».

Выражение, заключённое в «\(» и «\)» и сопровождаемое «*», следует считать неправильным. В некоторых случаях, оно соответствует нулю или более вхождений строки, которая была заключена в скобки. В других, оно соответствует выражению, заключённому в скобки, учитывая символ «*».

\{x ,y \} Соответствует последнему (предстоящему ) блоку, встречающемуся не менее x и не более y раз. Например, «a\{3,5\}» соответствует «aaa», «aaaa» или «aaaaa». В отличие от других операторов, этот (в традиционном синтаксисе) требует бэкслеша.
.* Обозначение любого количества любых символов между двумя частями регулярного выражения.

Метасимволы нам помогают использовать различные соответствия. Но как же представить метасимвол обычным символом, то есть символ [ (квадратная скобка) значением квадратной скобки? Просто:

  • необходимо предварить (экранировать ) метасимвол (. * + \ ? { }) обратным слешем. Например \. или \[

Для упрощения задания некоторых наборов символов, их объединили в т.н.классы и категории символов . POSIX стандартизовал объявление некоторых классов и категорий символов, как показано в следующей таблице:

POSIX класс аналогично обозначение
[:upper:] символы верхнего регистра
[:lower:] символы нижнего регистра
[:alpha:] символы верхнего и нижнего регистра
[:alnum:] цифры, символы верхнего и нижнего регистра
[:digit:] цифры
[:xdigit:] шестнадцатеричные цифры
[:punct:] [.,!?:…] знаки пунктуации
[:blank:] [ \t] пробел и TAB
[:space:] [ \t\n\r\f\v] символы пропуска
[:cntrl:] символы управления
[:graph:] [^ \t\n\r\f\v] символы печати
[:print:] [^\t\n\r\f\v] символы печати и символы пропуска

В regex есть такое понятие как:

Жадность regex

Постараюсь описать как можно понятней. Допустим, мы хотим найти все HTML теги в каком-то тексте. Локализовав задачу, мы хотим найти значения заключенные между < и >, вместе с этими самыми скобками. Но мы знаем, что теги имеют разную длину и самих тегов, как минимум штук 50. Перечислять их все, заключив в метасимволы - задача слишком трудоемкая. Но мы знаем, что у нас есть выражение.* (точка звездочка), характеризующее любое число любых символов в строке. С помощью данного выражения мы попытаемся найти в тексте (

Итак, Как создать RAID уровня 10/50 на контроллере LSI MegaRAID (актуально и для: Intel SRCU42x, Intel SRCS16):

) все значения между < и >. В результате, этому выражению будет соответствовать ВСЯ строка. почему, потому что регекс - ЖАДЕН и старается захватить ЛЮБОЕ ВСЕ количество символов между < и >, соответственно вся строка, начиная < p>Итак,... и заканчивая ...> будет принадлежать данному правилу!

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

  • учесть символы, не соответствующие желаемому образцу (например: <[^>]*> для вышеописанного случая)
  • избавить от жадности, добавив определении квантификатора, как нежадного:
    • *? - «не жадный» («ленивый») эквивалент *
    • +? - «не жадный» («ленивый») эквивалент +
    • {n,}? - «не жадный» («ленивый») эквивалент {n,}
    • .*? - «не жадный» («ленивый») эквивалент.*

Все вышенаписанное хочу дополнить синтаксисом расширенных регулярных выражений:

Регулярные выражения в POSIX аналогичны традиционному Unix-синтаксису, но с добавлением некоторых метасимволов:

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

Знак вопроса делает предыдущий символ или группу необязательной. Другими словами, в соответствующей строке она может отсутствовать, либо присутствовать ровно один раз.

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

Также было отменено использование обратной косой черты: \{…\} становится {…} и \(…\) становится (…).

В завершение поста, приведу некоторые примеры использования regex:

$ cat text1 1 apple 2 pear 3 banana $ grep p text1 1 apple 2 pear $ grep pea text1 2 pear $ grep "p*" text1 1 apple 2 pear 3 banana $ grep "pp*" text1 1 apple 2 pear $ grep "x" text1 $ grep "x*" text1 1 apple 2 pear 3 banana $ cat text1 | grep "l\|n" 1 apple 3 banana $ echo -e "find an\n* here" | grep "\*" * here $ grep "pp\+" text1 # строки, с содержанием одной р и 1 и более р 1 apple $ grep "pl\?e" text1 1 apple 2 pear $ grep "pl\?e" text1 # pe с возможным символом l 1 apple 2 pear $ grep "p.*r" text1 # p, в строках где есть r 2 pear $ grep "a.." text1 # строки с a, за которой следует как минимум 2 символа 1 apple 3 banana $ grep "\(an\)\+" text1 # Поиск более повторения an 3 banana $ grep "an\(an\)\+" text1 # поиск 2х повторений an 3 banana $ grep "" text1 # поиск строк, где есть 3 или p 1 apple 2 pear 3 banana $ echo -e "find an\n* here\nsomewhere." | grep "[.*]" * here somewhere. $ # Ищет символы от 3 до 7 $ echo -e "123\n456\n789\n0" | grep "" 123 456 789 $ # Ищем цифру, за которой до конца строки нет букв n и r $ grep "[[:digit:]][^nr]*$" text1 1 apple $ sed -e "/\(a.*a\)\|\(p.*p\)/s/a/A/g" text1 # замена а на А во всех строках, где после а идет а или после р идет р 1 Apple 2 pear 3 bAnAnA $ sed -e "/^[^lmnXYZ]*$/s/ear/each/g" text1 # замена ear на each в строках не начинающихся на lmnXYZ 1 apple 2 peach 3 banana $ echo "First. A phrase. This is a sentence." |\ # замена последнего слова в предложении на LAST WORLD. > sed -e "s/ [^ ]*\./ LAST WORD./g" First. A LAST WORD. This is a LAST WORD.

Предыстория и источник: не все, кому приходится использовать регулярные выражения, до конца понимают, как они работают и как их создавать. Я тоже относился к этой группе - искал примеры регулярных выражений, подходящих под мои задачи, пытался их подправить по мере необходимости. Для меня всё в корне изменилось после прочтения книги The Linux Command Line (Second Internet Edition) автора William E. Shotts, Jr. В ней принципы работы регулярных выражений изложены настолько ясно, что после прочтения я научился их понимать, создавать регулярные выражения любой сложности и теперь использую их при каждой необходимости. Данный материал представляет собой перевод части главы, посвящённой регулярным выражениям. Этот материал предназначен для абсолютных новичков, которые совершенно не понимают, как работают регулярные выражения, но имеют некоторые представления о работе . Надеюсь, эта статья поможет вам сделать такой же прорыв, который помогла мне. Если изложенный здесь материал не содержит ничего нового для вас, попробуйте посмотреть статью «Регулярные выражения и команда grep », в ней более подробно описываются опции grep, а также имеются дополнительные примеры.

Как используются регулярные выражения

Текстовые данные играют важную роль во всех Unix-подобных системах, таких как Linux. Среди прочего, текстом является и вывод консольных программ, и файлы конфигурации, отчётов и т.д. Регулярные выражения являются (пожалуй) одной из самых сложных концепций по работе с текстом, поскольку предполагают высокий уровень абстракции. Но время, потраченное на их изучение, с лихвой окупится. Умея использовать регулярные выражения, вы сможете делать удивительные вещи, хотя их полная ценность может быть не сразу очевидной.

В этой статье будет рассмотрено использование регулярных выражений вместе с командой grep . Но их применение не ограничивается только этим: регулярные выражения поддерживаются другими командами Linux, многими языками программирования, применяются при конфигурации (например, в настройках правил mod_rewrite в Apache), а также некоторые программы с графическим интерфейсом позволяют устанавливать правила для поиска/копирования/удаления с поддержкой регулярных выражений. Даже в популярной офисной программе Microsoft Word для поиска и замены текста вы можете использовать регулярные выражения и подстановочные символы.

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

Говоря простым языком, регулярное выражение - это условное обозначение, символическая запись шаблона, который ищется в тексте. Регулярные выражения поддерживаются многими инструментами командной строки и большинством языков программирования и применяются для облегчения решения проблем с текстовыми манипуляциями. Однако (будто мало нам их сложности), не все регулярные выражения одинаковы. Они немного меняются от инструмента к инструменту и от языка программирования до языка. Для нашего обсуждения мы ограничимся регулярными выражениями, описанными в стандарте POSIX (который будет охватывать большинство инструментов командной строки), в отличие от многих языков программирования (в первую очередь Perl), которые используют несколько более крупные и более богатые наборы нотаций.

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 "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 "^" dirlist*.txt MAKEDEV GET HEAD POST VBoxClient X X11 Xorg ModemManager NetworkManager VBoxControl VBoxService

Суть в том, что мы разместили все 26 заглавных букв в выражение внутри квадратных скобок. Но мысль печатать их все не вызывает энтузиазма, поэтому есть другой путь:

Grep -h "^" dirlist*.txt

Используя трёхсимвольный диапазон, мы можем сократить запись из 26 букв. Таким способом можно выразить любой диапазон символов, включая сразу несколько диапазонов, такие, как это выражение, которое соответствует всем именам файлов, начинающихся с букв и цифр:

Grep -h "^" dirlist*.txt

В диапазонах символов мы видим, что символ чёрточки трактуется особым образом, поэтому как мы можем включить символ тире в выражение внутри квадратных скобок? Сделав его первым символом в выражении. Рассмотрим два примера:

Grep -h "" dirlist*.txt

Это будет соответствовать каждому имени файла, содержащему заглавную букву. При этом:

Grep -h "[-AZ]" dirlist*.txt

будет соответствовать каждому имени файла, содержащему тире, или заглавную «A», или заглавную «Z».

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

  • Проверка ввода текста;
  • Поиск и замена текста в файле;
  • Пакетное переименование файлов;
  • Взаимодействие с сервисами, таким как Apache;
  • Проверка строки на соответствие шаблону.

Это далеко не полный список, регулярные выражения позволяют делать намного больше. Но для новых пользователей они могут показаться слишком сложными, поскольку для их формирования используется специальный язык. Но учитывая предоставляемые возможности, регулярные выражения Linux должен знать и уметь использовать каждый системный администратор.

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

В регулярных выражениях могут использоваться два типа символов:

  • обычные буквы;
  • метасимволы.

Обычные символы — это буквы, цифры и знаки препинания, из которых состоят любые строки. Все тексты состоят из букв и вы можете использовать их в регулярных выражениях для поиска нужной позиции в тексте.

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

обычный_символ спецсимвол_оператор

спецсимвол_замены спецсимвол_оператор

  • — с обратной косой черты начинаются буквенные спецсимволы, а также он используется если нужно использовать спецсимвол в виде какого-либо знака препинания;
  • ^ — указывает на начало строки;
  • $ — указывает на конец строки;
  • * — указывает, что предыдущий символ может повторяться 0 или больше раз;
  • + — указывает, что предыдущий символ должен повторится больше один или больше раз;
  • ? — предыдущий символ может встречаться ноль или один раз;
  • {n} — указывает сколько раз (n) нужно повторить предыдущий символ;
  • {N,n} — предыдущий символ может повторяться от N до n раз;
  • . — любой символ кроме перевода строки;
  • — любой символ, указанный в скобках;
  • х|у — символ x или символ y;
  • [^az] — любой символ, кроме тех, что указаны в скобках;
  • — любой символ из указанного диапазона;
  • [^a-z] — любой символ, которого нет в диапазоне;
  • b — обозначает границу слова с пробелом;
  • B — обозначает что символ должен быть внутри слова, например, ux совпадет с uxb или tuxedo, но не совпадет с Linux;
  • d — означает, что символ — цифра;
  • D — нецифровой символ;
  • n — символ перевода строки;
  • s — один из символов пробела, пробел, табуляция и так далее;
  • S — любой символ кроме пробела;
  • t — символ табуляции;
  • v — символ вертикальной табуляции;
  • w — любой буквенный символ, включая подчеркивание;
  • W — любой буквенный символ, кроме подчеркивания;
  • uXXX — символ Unicdoe.

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

Например, вы хотите найти в тексте строку 1+ 2=3. Если вы используете эту строку в качестве регулярного выражения, то ничего не найдете, потому что система интерпретирует плюс как спецсимвол, который сообщает, что предыдущая единица должна повториться один или больше раз. Поэтому его нужно экранировать: 1 + 2 = 3. Без экранирования наше регулярное выражение соответствовало бы только строке 11=3 или 111=3 и так далее. Перед равно черту ставить не нужно, потому что это не спецсимвол.

Примеры использования регулярных выражений

Теперь, когда мы рассмотрели основы и вы знаете как все работает, осталось закрепить полученные знания про регулярные выражения linux grep на практике. Два очень полезные спецсимвола — это ^ и $, которые обозначают начало и конец строки. Например, мы хотим получить всех пользователей, зарегистрированных в нашей системе, имя которых начинается на s. Тогда можно применить регулярное выражение «^s» . Вы можете использовать команду egrep:

egrep "^s" /etc/passwd

Если мы хотим отбирать строки по последнему символу в строке, что для этого можно использовать $. Например, выберем всех системных пользователей, без оболочки, записи о таких пользователях заканчиваются на false:

egrep "false$" /etc/passwd

Чтобы вывести имена пользователей, которые начинаются на s или d используйте такое выражение:

egrep "^" /etc/passwd

Такой же результат можно получить, использовав символ «|». Первый вариант более пригоден для диапазонов, а второй чаще применяется для обычных или/или:

egrep "^" /etc/passwd

Теперь давайте выберем всех пользователей, длина имени которых составляет не три символа. Имя пользователя завершается двоеточием. Мы можем сказать, что оно может содержать любой буквенный символ, который должен быть повторен три раза, перед двоеточием:

egrep "^w{3}:" /etc/passwd

Выводы

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

На завершение лекция от Яндекса про регулярные выражения:

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

Пользователи UNIX знакомы с регулярными выражениями по программам grep, sed, awk (или gawk) и ed. С помощью этих программ или их аналогов можно опробовать и проверить приводимые ниже примеры. Текстовые редакторы, такие как (X)Emacs и vi, также активно используют регулярные выражения. Возможно, самое известное и самое широкое использование регулярных выражений имеет место в языке Perl . Без знания регулярных выражений трудно обойтись разработчику ПО и системному администратору.

Метасимволы

Итак, строки могут состоять из букв, цифр и метасимволов. Метасимволами являются:

\ | () { } ^ $ * + ? . < >

Метасимволы могут играть в регулярном выражении следующие роли:

    квантификатор

    утверждение;

    знак группы;

    альтернатива;

    знак последовательности

Квантификаторы

Метасимвол * (звездочка) заменяет собой 0 или несколько символов. Метасимвол + (плюс) заменяет собой 1 или несколько символов. Метасимвол. (точка) заменяет собой ровно 1 произвольный символ. Метасимвол? (вопросительный знак) заменяет собой 0 или 1 символ. Различие в использовании * и + таково, что запрос на поиск строки с* даст любые строки, включая пустые, а запрос с+ - только строки, содержащие символ с.

Пустые строки подчиняются следующим договоренностям: в пустой строке содержится одна и только одна пустая строка; в непустой строке пустые строки содержатся перед каждым символом, а также в конце строки.

В регулярных выражениям используется также конструкция {n,m} , обозначающая, что символ, идущий перед конструкцией, встречается в строке от n до m раз. Опуская число m подразумеваем бесконечность. Т.е. частными случаями конструкции являются следующие записи: {0,} , {1,} и {0,1} . Первая соответствует * , вторая - метасимволу + , а третья - ? . Эти равенства легко получить из определения соответствующих квантификаторов. Кроме того, конструкция {n} означает, что символ встречается ровно n раз.

В связи с использованием в качестве метасимволов некоторых знаков препинания и математических символов введен дополнительный метасимвол \ (backslash, обратная косая черта), который будучи записан перед метасимволом превращает последний в обычный символ. Т.е. ? - это квантификатор, а \? - знак вопроса.

Группы

Описанные выше квантификаторы, как уже говорилось, действуют на ближайший к ним слева символ (последний предшествующий). Но это ограничение позволяют обойти группы, в обозначении которых используются метасимволы (и) . Эти символы выделяют из выражения подвыражение, объединяемое в группу, к которому затем и применяется квантификатор.

Пример:

означает (или заменяет собой)

Ho ho ho ho ho ho hohoho

Возможны вложения подвыражений, т.е. из подвыражения можно выделять подвыражения меньшей длины.

Альтернативы

Образуются при помощи метасимвола | (вертикальная черта), обозначающего логическое «или».

Пример : регулярное выражение коров(а|ы|е|у|ой|ою)? задает все возможные склонения слова «корова» в единственном числе по падежам.

Утверждения

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

^ начало строки $ конец строки < начало слова > конец слова

Пример : регулярное выражение $The позволяет найти строку, начинающуюся с The .

Замечание: обычные символы можно рассматривать как утверждения с ненулевой длиной.

Последовательности

Особая конструкция, заключенная в метасимволы [ и ] (прямоугольные скобки), позволяет перечислить варианты символов, которые могут стоять в регулярном выражении на данном месте, и называется последовательностью. Внутри прямоугольных скобок все метасимволы трактуются как простые символы, а символы - (минус) и ^ приобретают новые значения: первый позволяет задать непрерывную последовательность символов между двумя указанными, а второй дает логическое «не» (отрицание). Проще всего рассмотреть следующие примеры:

какая-либо из строчных латинских букв:

латинский буквенно-цифровой символ (от a до z , от A до Z и от 0 до 9):

символ, не являющийся латинским буквенно-цифровым:

[^a-zA-Z0-9]

любое слово (без дефисов, математических символов и цифр):

<+>

Для краткости и простоты вводятся следующие сокращения:

\d цифра (т.е. соответствует выражению ); \D не цифра (т.е. [^0-9]); \w латинское слово (буквенно-цифровое); \W последовательность символов без пробелов, не являющаяся латинским буквенно-цифровым словом ([^a-zA-Z0-9]); \s пустой промежуток [ \t\n\r\f] , т.е. пробелы, табуляция и т.д. \S непустой промежуток ([^ \t\n\r\f]).

Связь с групповыми символами

С групповыми символами знаком, наверное, каждый пользователь. Примером выражения с использованием группового символа является запись *.jpg , обозначающая все файлы с расширением jpg . Чем же регулярные выражения отличаются от групповых символов? Отличия можно суммировать в трех правилах преобразования произвольного выражения с групповыми символами в регулярное выражение:

    Заменить * на.*

    Заменить? на.

    Заменить все символы, совпадающие с метасимволами, на их бэкслэшированные варианты.

Действительно, в регулярном выражении запись * бесполезна и дает пустую строку, т.к. означает, что пустая строка повторяется сколь угодно раз. А вот.* (повторить произвольный символ сколь угодно много раз, включая 0) как раз совпадает по смыслу с символом * в множестве групповых символов.

Регулярное выражение, соответствующее *.jpg , будет выглядеть так: .*\.jpg . А, например, последовательности групповых символов ez*.pp соответствуют два эквивалентных регулярных выражения - ez.*\.pp и ez.*\.(cpp|hpp) .

Примеры регулярных выражений

E-mail в формате [email protected]

+(\.+)*@+(\.+)+

E-mail в формате "Иван Иванов "

("?+"?[ \t]*)+\<+(\.+)*@+(\.+)+\>

Проверка web-протокола в URL (http:// , ftp:// или https://)

+://

Некоторые команды и директивы C/C++:

^#include[ \t]+[<"][^>"]+[">] - директива include

//.+$ - комментарий на одной строке

/\*[^*]*\*/ - комментарий на нескольких строках

-?+\.+ - число с плавающей точкой

0x+ - число в шестнадцатиричной системе счисления.

А вот, например, программа поиска слова cow:

grep -E "cow|vache" * >/ dev/ null && echo "Found a cow"

Здесь опция -E используется для включения поддержки расширенного синтаксиса регулярных выражений.

Текст составлен на основе статьи Жана Борсоди (Jan Borsodi) из файла HOWTO-regexps.htm

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

Непрерывные выражения (англ. regular expressions, сокр. RegExp, RegEx, жарг. регэкспы или регексы) - система синтаксического разбора текстовых фрагментов по формализованному шаблону, основанная на системе записи образцов для поиска. Образец (англ. pattern) задает правило поиска, по-русски также иногда кликается «шаблоном», «маской». Регулярные выражения произвели прорыв в электронной обработке контента в конце XX века. Они представляются развитием символов-джокеров (англ. wildcard characters).

Сейчас постоянные выражения используются многочисленными текстовыми редакторами и утилитами для поиска и изменения текста на базе выбранных правил. Почти многие языки программирования поддерживают регулярные выражения для работы со строчками. Например, Java, .NET Framework, Perl, PHP, JavaScript, Python и др. обладают встроенную поддержку постоянных выражений. Набор утилит (включая редактор sed и фильтр grep), считаемых в дистрибутивах UNIX, одним из первоначальных способствовал популяризации понятия регулярных выражений.

Одна из более полезных и многофункциональных команд в терминале Linux – бригада «grep». Grep – это акроним, какой расшифровывается как «global regular expression print» (то имеется, «искать везде соответствующие постоянному выражению строки и выводить их»).

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

Назначение grep - поиск строк согласно условию, изображенному регулярным выражением. Существуют изменения классического grep - egrep, fgrep, rgrep. Все они отточены под конкретные цели, при этом способности grep перекрывают весь функционал. Самым несложным примером использования команды представляется вывод строки, удовлетворяющей шаблону, из файла. Пример мы хотим найти строку, сохраняющую ‘user’ в файле /etc/mysql/my.cnf. Для этого воспользуемся последующей командой:

Grep user /etc/mysql/my.cnf

Grep сможет просто искать конкретное словечко:

Grep Hello ./example.cpp

Или строку, но в таком варианте её нужно заключать в кавычки:

Grep "Hello world" ./example.cpp

В добавление альтернативами программы являются egrep и fgrep, которые являются тем же самым, что и, соответственно, grep -E и grep -F. Варианты egrep и fgrep являются устаревшими, но работают для обратной совместимости. Вместо устаревших вариантов рекомендуется использовать grep -E и grep –F.

Команда grep сопоставляет строки исходных файлов с шаблоном, этим базовым регулярным выражением. Если файлы не указаны, используется стандартный ввод. Как как обычно каждая успешно сопоставленная строка копируется на стандартный вывод; если
исходных файлов чуть-чуть, перед найденной строкой выдается имя файла. В качестве шаблонов воспринимаются базовые непрерывные выражения (выражения, имеющие своими значениями цепочки символов, и использующие ограниченный комплекс алфавитно-цифровых и специальных символов).

Использование egrep в Linux

Egrep или grep -E - это другая версия grep или Extended grep. Эта версия grep превосходна и быстра, когда дело доходит до поиска шаблона регулярных выражений, поскольку она обрабатывает метасимволы как есть и не заменяет их как строки. Egrep использует ERE или Extended Extended Expression.

egrep - это урезанный вызов grep c ключом -E Отличие от grep заключается в возможности использовать расширенные непрерывные выражения с использованием символьных классов POSIX. Часто возникает задача поиска словечек или представлений, принадлежащих к одному типу, но с возможными вариациями в написании, такие как даты, фамилии файлов с некоторым расширением и стандартным названием, e-mail адреса. С другой стороны, имеется задачи по пребыванию вполне определенных слов, которые могут иметь различное начертание, либо розыск, исключающий отдельные символы или классы символов.

Для этих целей истины созданы некоторые системы, основанные на описании текста при помощи шаблонов. К таким системам причисляются и постоянные выражения. Два очень полезные спецсимвола — это ^ и $, которые обозначают начало и конец строки. Например, мы хотим получить всех пользователей, зарегистрированных в нашей системе, имя которых начинается на s. Тогда можно применить регулярное выражение «^s». Вы можете использовать бригаду egrep:

Egrep "^s" /etc/passwd

Есть возможность поиска по нескольким файлам и в подобном случае перед строкой выводится имя файла.

Egrep -i Hello ./example.cpp ./example2.cpp

А следующий запрос выводит весь код, исключая строки, содержащие только комментарии:

Egrep -v ^/ ./example.cpp

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

Использование fgrep в Linux

Fgrep или Fixed grep или grep -F - это еще одна версия grep, какой-никакая необходима, когда дело доходит до поиска всей строки вместо регулярного понятия, поскольку оно не распознает ни регулярные выражения, ни метасимволы. Для поиска любой строки напрямую выбирайте эту версия grep.

Fgrep ищет полную строку и не распознает специальные символы как часть непрерывного выражения, несмотря на то экранированы символы или нет.

Fgrep -C 0 "(f|g)ile" check_file fgrep -C 0 "\(f\|g\)ile" check_file

Использование sed в Linux

sed (от англ. Stream EDitor) - потоковый текстовый редактор (а также язычок программирования), использующий различные предопределённые текстовые преобразования к последовательному потоку текстовых этих. Sed можно утилизировать как grep, выводя строки по шаблону базового регулярного выражения:

Sed -n /Hello/p ./example.cpp

Может быть использовать его для удаления строк (удаление всех пустых строк):

Sed /^$/d ./example.cpp

Основным инструментом работы с sed является выражение типа:

Sed s/искомое_выражение/чем_заменить/имя_файла

Так, образчик, если выполнить команду:

Sed s/int/long/ ./example.cpp

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

Поделиться