Наведені приклади регулярних виразів. П'ять прикладів використання 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):

) всі значення між< и >. В результаті, цьому виразу буде відповідати ВСЯ рядок. чому, тому що регекс - ЖАДЕНИЙ і намагається захопити БУДЬ-ВСЕ кількість символів між< и >відповідно весь рядок, починаючи < Отже,...і закінчуючи ...> належатиме цьому правилу!

Сподіваюся, на прикладі зрозуміло, що таке жадібність. Щоб позбутися цієї жадібності, можна піти наступним шляхом:

  • врахувати символи, невідповідні бажаному зразку (наприклад:<[^>]*> для вищеописаного випадку)
  • позбавити від жадібності, додавши визначенні квантифікатора, як нежадібного:
    • *? - «не жадібний» («ледачий») еквівалент *
    • +? - «не жадібний» («ледачий») еквівалент +
    • (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$" dir *.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 послідовність символів без пробілів, що не є латинським буквенно-цифровим словом ([^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) задає правило пошуку, російською також іноді зветься «шаблоном», «маскою». Регулярні висловлювання зробили прорив у електронній обробці контенту наприкінці ХХ століття. Вони є розвитком символів-джокерів (англ. 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 з ключем -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.

Поділитися