103.7 Урок 1
Сертифікат: |
LPIC-1 |
---|---|
Версія: |
5.0 |
Розділ: |
103 GNU та команди Unix |
Тема: |
103.7 Пошук текстових файлів за допомогою регулярних виразів |
Урок: |
1 з 2 |
Вступ
Алгоритми пошуку рядків настільки широко використовуються в різних задачах обробки даних, що операційні системи, подібні Unix, мають свою власну загальну реалізацію: Регулярні вирази, часто скорочено REs (Regular expressions). Регулярні вирази складаються з послідовностей символів, які утворюють загальний шаблон, що використовується для пошуку та іноді модифікації відповідної послідовності в більшому рядку символів. Регулярні вирази значно розширюють можливості:
-
Написання правил для синтаксичного аналізу запитів на HTTP-серверах, зокрема nginx.
-
Написання сценаріїв, які перетворюють текстові набори даних в інший формат.
-
Пошуку цікавих входжень у записах журналів або документах.
-
Фільтрування розмітки у документах зі збереженням семантичного вмісту.
Найпростіший регулярний вираз містить принаймні один атом. Атом, називається так тому, що він є основним елементом регулярного виразу, — це просто символ, який може мати або не мати особливе значення. Більшість звичайних символів однозначні, вони зберігають своє буквальне значення, а інші мають особливе значення:
.
(крапка)-
Атом відповідає будь-якому символу.
^
(каретка)-
Атом збігається з початком рядка.
$
(знак долара)-
Атом збігається з кінцем рядка.
Наприклад, регулярний вираз bc
, що складається з символьних атомів b
і c
, можна знайти в рядку abcd
, але не можна знайти в рядку a1cd
. З іншого боку, регулярний вираз .c
можна знайти в обох рядках abcd
і a1cd
, оскільки крапка .
збігається з будь-яким символом.
Атоми каретки та знака долара використовуються, коли нас цікавлять лише збіги на початку чи в кінці рядка. З цієї причини їх також називають якорями. Наприклад, cd
можна знайти в abcd
, але ^cd
не можна. Аналогічно, ab
можна знайти в abcd
, але ab$
не можна. Каретка ^
є літеральним символом, за винятком випадків, коли вона знаходиться на початку, а $
є літеральним символом, за винятком випадків, коли символ розташований в кінці регулярного виразу.
Вираз у дужках
Існує інший тип атома під назвою вираз у дужках. Хоча дужки []
(разом з їх вмістом) не є одним символом, вони вважаються одним атомом. Вираз у дужках зазвичай являє собою лише список літеральних символів, охоплених []
, завдяки чому атом відповідає будь-якому окремому символу зі списку. Наприклад, вираз [1b]
можна знайти в обох рядках abcd
і a1cd
. Щоб вказати символи, яким атом не повинен відповідати, список має починатися з ^
, як у [^1b]
. Також можна вказати діапазони символів у виразах у дужках. Наприклад, [0−9]
відповідає цифрам від 0 до 9, а [a−z]
відповідає будь-якій літері нижнього регістру. Діапазони слід використовувати з обережністю, оскільки вони можуть не узгоджуватися в різних регіонах.
Списки з виразами у дужках також приймають класи, а не лише окремі символи та діапазони. Традиційні символьні класи:
[:alnum:]
-
Представляє буквено-цифровий символ.
[:alpha:]
-
Представляє символ алфавіту.
[:ascii:]
-
Представляє символ, який входить до набору символів ASCII.
[:blank:]
-
Представляє порожній символ, тобто пробіл або табуляцію.
[:cntrl:]
-
Представляє керуючий символ.
[:digit:]
-
Представляє цифру (від 0 до 9).
[:graph:]
-
Представляє будь-який друкований символ, крім пробілу.
[:lower:]
-
Представляє символ нижнього регістру.
[:print:]
-
Представляє будь-який друкований символ, включаючи пробіл.
[:punct:]
-
Представляє будь-який друкований символ, який не є пробілом чи буквено-цифровим символом.
[:space:]
-
Представляє символи пробілів: пробіл, нова сторінка (
\f
), новий рядок (\n
), повернення каретки (\r
), горизонтальна табуляція (\t
) і вертикальна табуляція (\v
). [:upper:]
-
Представляє велику літеру.
[:xdigit:]
-
Представляє шістнадцяткові цифри (від 0 до F).
Класи символів можна комбінувати з окремими символами та діапазонами, але не можна використовувати як кінцеву точку діапазону. Крім того, класи символів можуть використовуватися лише з виразами у дужках, а не як незалежний атом поза дужками.
Квантори
Досяжність атома, атома з одним символом або атома в дужках можна налаштувати за допомогою атому квантора. Квантори атома визначають послідовності атома, тобто збіги відбуваються, коли в рядку знайдено безперервне повторення для атома. Підрядок, що відповідає збігу, називається piece. Незважаючи на це, квантори та інші функції регулярних виразів трактуються по-різному залежно від того, який стандарт використовується.
Згідно з визначенням POSIX, існують дві форми регулярних виразів: «базові» та «розширені» регулярні вирази. Більшість текстових програм у будь-якому звичайному дистрибутиві Linux підтримують обидві форми, тому важливо знати їх відмінності, щоб уникнути проблем із сумісністю та вибрати найбільш підходящу реалізацію для поставленого завдання.
Квантор *
виконує однакову функцію як в базових, так і в розширених регулярних виразах (атом зустрічається нуль або більше разів), і він є буквеним символом, якщо він з’являється на початку регулярного виразу або якщо йому передує зворотна коса риска \
. Квантор ` вибирає фрагменти, що містять один або кілька збігів атомів у послідовності. За допомогою квантора знака питання `?` збіг відбудеться, якщо відповідний атом з’явиться один раз або не з’явиться взагалі. Якщо перед ним стоїть зворотна коса риска `\`, їх особливе значення не враховується. Основні регулярні вирази також підтримують квантори `
і ?
, але перед ними має бути зворотний слеш. На відміну від розширених регулярних виразів, +
і ?
самі по собі є буквеними символами в базових регулярних виразах.
Межі
bound — це квантор атома, який, як випливає з назви, дозволяє користувачеві вказувати точні кількісні межі для атома. У розширених регулярних виразах bound може відображатися в трьох формах:
{i}
-
Атом повинен з’являтися рівно
i
разів (i
– ціле число). Наприклад,[[:blank:]]{2}
збігається з двома пустими символами. {i,}
-
Атом має з’явитися принаймні
i
разів (i
- ціле число). Наприклад,[[:blank:]]{2,}
збігається з будь-якою послідовністю з двох або більше порожніх символів. {i,j}
-
Атом має з’являтися принаймні
i
і не більше ніжj
разів (i
іj
- цілі числа,j
більше ніжi
). Наприклад,xyz{2,4}
відповідає рядкуxy
, за яким слідують два-чотири символиz
.
У будь-якому випадку, якщо підрядок збігається з регулярним виразом і довший підрядок, що починається в тій же точці, також збігається, буде розглядатися довший підрядок.
Основні регулярні вирази також підтримують bounds, але перед роздільниками має стояти \
: \{
та \}
. Самі по собі {
та }
інтерпретуються як літеральні символи. \{
, за яким слідує символ, відмінний від цифри, є літеральним символом, а не початком bound.
Гілки та зворотні посилання
Базові регулярні вирази також відрізняються від розширених регулярних виразів ще одним важливим аспектом: розширений регулярний вираз можна розділити на гілки, кожна з яких є незалежним регулярним виразом. Гілки відокремлюються символом |
, і комбінований регулярний вираз буде відповідати співпаданню за будь-якою з гілок. Наприклад, he|him
буде збігатися, якщо підрядок he
або him
знайдено в рядку, що перевіряється. Основні регулярні вирази інтерпретують |
як буквальний символ. Однак більшість програм, що підтримують базові регулярні вирази, дозволять розгалуження з \|
.
Розширений регулярний вираз, вміщений у ()
, можна використовувати у зворотному посиланні_. Наприклад, ([[:digit:]])\1
відповідатиме будь-якому регулярному виразу, який повторюється принаймні один раз, оскільки \1
у виразі є зворотним посиланням на фрагмент, який відповідає першому в дужках підвиразу. Якщо в регулярному виразі існує більше одного підвиразу в дужках, на них можна посилатися \2
, \3
тощо.
Для базових регулярних виразів підвирази мають бути охоплені \(
і \)
, а (
і )
самі по собі є звичайними символами. Індикатор зворотного посилання використовується для розширених регулярних виразів.
Пошук за допомогою регулярних виразів
Безпосередньою перевагою регулярних виразів є покращення пошуку у файлових системах і в текстових документах. Параметр -regex
команди find
дозволяє перевірити кожен шлях в ієрархії каталогів на регулярний вираз. Наприклад,
$ find $HOME -regex '.*/\..*' -size +100M
шукає файли розміром понад 100 мегабайт (100 блоків з 1048576 байт), але лише в шляхах у домашньому каталозі користувача, які містять збіг із .*/\..*
, тобто /.
оточений будь-якою іншою кількістю символів. Іншими словами, будуть виведені лише приховані файли або файли всередині прихованих каталогів, незалежно від позиції /.
у відповідному шляху. Для регулярних виразів, не чутливих до регістру, натомість слід використовувати параметр -iregex
:
$ find /usr/share/fonts -regextype posix-extended -iregex '.*(dejavu|liberation).*sans.*(italic|oblique).*' /usr/share/fonts/dejavu/DejaVuSansCondensed-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansCondensed-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSans-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSans-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-Oblique.ttf /usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf /usr/share/fonts/liberation/LiberationSans-Italic.ttf
У цьому прикладі регулярний вираз містить гілки (написані в розширеному стилі), щоб вивести лише певні файли шрифтів в ієрархії каталогу /usr/share/fonts
. Розширені регулярні вирази не підтримуються за замовчуванням, але find
дозволяє увімкнути їх підтримку за допомогою -regextype posix-extended
або -regextype egrep
. Стандартним регулярним виразом за замовчуванням для find
є findutils-default, який практично є базовим клоном регулярного виразу.
Часто необхідно передати виведення програми команді less
, якщо воно не поміщається на екрані. Команда less
розбиває введені дані на сторінки, по одному екрану, що дозволяє користувачеві легко переміщатися текстом вгору і вниз. Крім того, less
також дозволяє користувачеві виконувати пошук на основі регулярних виразів. Ця функція особливо важлива, оскільки less
— це стандартний пагінатор, який використовується для багатьох повсякденних завдань, таких як перевірка записів у журналі або перегляд man-сторінок. Під час читання man-сторінки, наприклад, натискання клавіші / відкриє підказку пошуку. Це типовий сценарій, у якому регулярні вирази корисні, оскільки параметри команд перераховані відразу після поля сторінки в загальному макеті man-сторінки. Проте один і той самий параметр може з’являтися багато разів у тексті, що робить пошук за літералами неможливим. Незалежно від цього, якщо ввести ^[[:blank:]]*-o
— або простіше: ^ *-o
— у підказці пошуку ви одразу перейде до параметра розділу -o
(якщо він існує) після натискання клавіші Enter, що дозволяє швидше ознайомитися з описом параметру.
Вправи до посібника
-
Який розширений регулярний вираз відповідатиме будь-якій електронній адресі, наприклад
info@example.org
? -
Який розширений регулярний вираз відповідатиме лише будь-якій IPv4-адресі у стандартному форматі з крапками, наприклад
192.168.15.1
? -
Як можна використовувати команду
grep
для виведення вмісту файлу/etc/services
, відкидаючи всі коментарі (рядки, що починаються з#
)? -
Файл
domains.txt
містить список доменних імен, по одному на рядок. Як використовувати командуegrep
для відображення лише доменів.org
або.com
?
Дослідницькі вправи
-
Як у поточному каталозі команда
find
використовуватиме розширений регулярний вираз для пошуку всіх файлів, які не містять стандартного суфікса (наприклад, назви файлів не закінчуються на.txt
або.c
)? -
Команда
less
є стандартним інструментом для відображення довгих текстових файлів у середовищі оболонки. Набравши/
, можна ввести регулярний вираз до підказки пошуку, щоб перейти до першого відповідного збігу. Щоб залишитися в поточній позиції документа і виділити лише відповідні збіги, яку комбінацію клавіш потрібно ввести до підказки пошуку? -
Як можна було б відфільтрувати виведення у
less
, щоб відображалися лише рядки, які відповідають регулярному виразу?
Підсумки
Цей урок охоплює загальну підтримку Linux регулярних виразів, стандарту, що широко використовується, чиї можливості зіставлення шаблонів підтримуються більшістю програм, які працюють з текстом. Урок розглядає наступні питання:
-
Що таке регулярний вираз.
-
Основні компоненти регулярного виразу.
-
Відмінності між регулярними та розширеними регулярними виразами.
-
Як виконувати простий пошук тексту та файлів за допомогою регулярних виразів.
Відповіді на вправи до посібника
-
Який розширений регулярний вираз відповідатиме будь-якій електронній адресі, наприклад
info@example.org
?egrep "\S+@\S+\.\S+"
-
Який розширений регулярний вираз відповідатиме лише будь-якій IPv4-адресі у стандартному форматі з крапками, наприклад
192.168.15.1
?egrep "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
-
Як можна використовувати команду
grep
для виведення вмісту файлу/etc/services
, відкидаючи всі коментарі (рядки, що починаються з#
)?grep -v ^# /etc/services
-
Файл
domains.txt
містить список доменних імен, по одному на рядок. Як використовувати командуegrep
для відображення лише доменів.org
або.com
?egrep ".org$|.com$" domains.txt
Відповіді до дослідницьких вправ
-
Як у поточному каталозі команда
find
використовуватиме розширений регулярний вираз для пошуку всіх файлів, які не містять стандартного суфікса (наприклад, назви файлів не закінчуються на.txt
або.c
)?find . -type f -regextype egrep -not -regex '.*\.[[:alnum:]]{1,}$'
-
Команда
less
є стандартним інструментом для відображення довгих текстових файлів у середовищі оболонки. Набравши/
, можна ввести регулярний вираз до підказки пошуку, щоб перейти до першого відповідного збігу. Щоб залишитися в поточній позиції документа і виділити лише відповідні збіги, яку комбінацію клавіш потрібно ввести до підказки пошуку?Натисканням Ctrl+K перед введенням виразу пошуку.
-
Як можна було б відфільтрувати виведення у
less
, щоб відображалися лише рядки, які відповідають регулярному виразу?Натиснувши & і ввівши вираз для пошуку.