Регулярные выражения в Linux
 
Регулярные выражения используются для расширенного контекстного поиска и модификации текста. Они могут быть использованы во многих Linux-программах вроде профессиональных редакторов, в программах синтаксического анализа (parser programs) и в языках программирования.

Регулярные выражения применяются во многих редакторах, таких как vi и emacs, в программах grep/egrep и языках, таких как awk, perl и sed.
Регулярные выражения используются для расширенного контекстного поиска и модификации текста. Регулярное выражение — это формальное описание шаблона, который соответствует текстовой строке.
Когда используешь регулярные выражения, то все становится просто и удобно. Задачи редактирования и поиска текста, которые обычно занимают часы, могут быть выполнены просто за несколько секунд. Однако не всем понятны выражения, которые используются для упрощения жизни. Они выглядят как странная комбинация точек, слешей, звездочек и некоторых других символов. На самом деле они очень легки в использовании. Они подчиняются нескольким простым синтаксическим правилам.
Хотя регулярные выражения очень широко распространены в мире Linux/Unix, но не существует такой штуки, как "стандартный язык регулярных выражений". Есть несколько различных диалектов. Например, два типа программы grep: grep и egrep. Обе используют регулярные выражения с незначительно отличающимися возможностями. Perl, возможно, имеет более полный набор регулярных выражений. К счастью, все они следуют общим принципам. Как только вы поймете основную идею, то вам будет легко изучить детали различных диалектов.
Эта статья введет вас в основы, и вы сможете изучить различные аспекты и возможности программ на их man-страницах.
Простой пример. Пусть вы имеете список телефонов компании и он выглядит подобно этому:
Phone Name ID
...
...
3412 Bob 123
3834 Jonny 333
1248 Kate 634
1423 Tony 567
2567 Peter 435
3567 Alice 535
1548 Kerry 534
...
Это компания, скажем, из 500 человек. Они хранят данные в простом текстовом файле. Человек с первой цифрой телефонного номера равной 1 работает в строении N1. Кто работает в строении 1?
Регулярные выражения, дающие ответ:
grep '^1' phonelist.txt
или
egrep '^1' phonelist.txt
или
perl -ne 'print if (/^1/)' phonelist.txt
На словах это значит: "искать все строки, которые начинаются с единицы". Символ "^" соответствует началу строки. Благодаря этому символу выражение соответствует только тем строкам, которые начинаются с единицы.
Рассмотрим синтаксис односимвольных шаблонов. Основным строительным блоком регулярных выражений является односимвольный шаблон. Он соответствует просто этому символу. Примером односимвольного шаблона является 1 в предыдущем примере. Она просто соответствует единице в тексте.

Другой пример односимвольного шаблона:
egrep 'Kerry' phonelist.txt
Этот шаблон состоит только из односимвольных шаблонов (буквы K,e...).
Символы могут быть сгруппированы вместе в класс. Класс представляется как пара из открывающей и закрывающей квадратных скобок и списка символов между ними. Класс представляет собой также односимвольный шаблон. Один и только один из этих символов должен присутствовать в тексте, который совпадет с шаблоном. Например:
— [abc] — односимвольный шаблон, который соответствует какой-либо из букв a, b или c.
— [ab0-9] — односимвольный шаблон, который соответствует либо a, либо b, либо цифре в интервале от нуля до девяти.
— [a-zA-Z0-9-] — соответствует букве в верхнем или нижнем регистре, цифре или знаку минус.
Попробуйте сделать следующее:
egrep '^1[348]' phonelist.txt
Эта команда выдаст строки, которые начинаются с 13 или 14 или 18.
Мы уже увидели, что большинство ASCII символов просто соответствуют этим же ASCII символам, но некоторые ASCII символы, называемые мета-символами, имеют специальное значение. Например, квадратные скобки ограничивают класс. Смысл "-" в классе это интервал. Чтобы отменить специальное значение мета-символа, нужно поставить перед ним обратный слеш. Пример этого — знак минус в [a-zA-Z0-9-]. В некоторых диалектах регулярных выражений мета-символы начинаются с обратного слеша. В этом случае вы должны удалить обратный слеш, чтобы получить нормальное значение символа.
Точка — это важный мета-символ. Она соответствует любому символу, кроме символа новой строки. Пример:
grep '^.2' phonelist.txt
или
egrep '^.2' phonelist.txt
Эти выражения используются для поиска строк с цифрой 2 во второй позиции и любым первым символом. 
Если определение класса начинается с "[^" вместо "[", то это означает отрицание этого класса (все символы кроме указанных). Теперь "^" больше не означает начало строки, но в комбинации с "[" обозначает отрицание класса.
— [^0-9] — соответствует любому одному НЕ цифровому символу.
— [^abc] — соответствует любому символу, который не a, b или c.
— . — точка соответствует любому символу, исключая символ новой строки. Это то же самое, как [^ ], где — символ новой строки.
Для нахождения всех строк, которые не начинаются с 1, мы можем написать:
grep '^[^1]' phonelist.txt
или
egrep '^[^1]' phonelist.txt
Фиксирование шаблонов. В предыдущей части мы уже увидели, что "^" соответствует началу строки. Фиксирование шаблонов производится при помощи специальных символов, которые соответствуют определенной позиции в тексте, а не просто символу.
— ^ — соответствует началу строки.
— $ — соответствует концу строки.
Чтобы найти человека с ID номер 567 в нашем phonelist.txt, мы можем использовать следующие команды:
egrep '567$' phonelist.txt
В результате мы получим строки с числом 567 в конце.
Множители. Множители определяют, сколько раз односимвольный шаблон повторяется в тексте.



Пример из телефонного списка:
....
1248 Kate 634
....
1548 Kerry 534
....
Для нахождения строк, которые начинаются с 1 и имеют несколько цифр, как минимум один пробел и имя, начинающееся с буквы К, мы можем написать:
grep '^1[0-9]{1,} {1,}K' phonelist.txt
или использовать * и повторить [0-9] и пробел:
grep '^1[0-9][0-9]* *K' phonelist.txt
или
egrep '^1[0-9]+ +K' phonelist.txt
или
perl -ne 'print if (/^1[0-9]+ +K/)' phonelist.txt
Множитель размножает предыдущий односимвольный шаблон. Так, "23*4" не означает "2, затем 3, затем что угодно и 4" (это выглядит как "23.*4"). А это означает "один раз 2, потом может быть несколько 3 и одна 4".
Также важно учесть, что множители обладают жадностью. Это означает, что действие первого множителя в шаблоне распространяется направо так далеко, как это возможно.
выражение ^1.*4
будет соответствовать всей строке
1548 Kerry 534
с начала и до самой последней 4.
Т.е. оно соответствует не только 154, а всей строке. Это не имеет большого значения для grep, но важно для редактирования и подстановки.
Круглые скобки как способ запоминания. Круглые скобки не изменяют действие выражения, при этом просто запоминается ограниченная скобками часть текста для того, чтобы можно было ссылаться на нее в выражении позднее.
Часть, которая была запомнена, доступна через переменные. Часть строки, ограниченная первой парой скобок, доступна через переменную один, вторая — через переменную два, и т.д.

Пример: выражение [a-z][a-z] будет соответствовать двум буквам в нижнем регистре. Теперь мы можем использовать эти переменные для создания шаблонов для поиска текста такого как 'otto' (зеркальные имена):
egrep '([a-z])([a-z])21'
Переменная 1 содержит букву о, и переменная 2 — букву t. Результат также будет содержать имя anna, но не olol.
Круглые скобки как способ запоминания не так часто используются для нахождения таких имен, как otto и anna, а применяются для редактирования и подстановки.
Использование регулярных выражений для редактирования текста. Для редактирования c использованием регулярных выражений вам необходим редактор, такой, как vi, emacs, или вы можете использовать, например, perl.
В emacs вы используете комбинацию Alt-X и команды query-replace-regexp или можете для этого переопределить любую функциональную клавишу. Также можете использовать команду replace-regexp. Команда query-replace-regexp интерактивная, другие нет.
В vi используется команда подстановки ':%s/ / /gc'. Процент определяет диапазон 'весь файл' и может быть заменен любым подходящим диапазоном. В vim вы нажимаете shift-v, помечаете область и тогда используете подстановку только в этой области. Довольно много написано в собственном руководстве к vim. Интерактивная версия команды — это 's/ / /gc', а не интерактивная — это 's/ / /g'. Интерактивность означает, что вы должны будете подтвердить, выполнять или нет подстановку в каждом случае.
В Perl'е вы можете использовать команду:
perl -pe 's/ / /g'
Посмотрим несколько примеров. План нумерации в нашей компании изменился, и во всех телефонных номерах, которые начинаются с 1, необходимо вставить 2 после второй цифры. Например, 1423 должно стать 14223.
Старый список:
Phone Name ID
...
3412 Bob 123
3834 Jonny 333
1248 Kate 634
1423 Tony 567
2567 Peter 435
3567 Alice 535
1548 Kerry 534
...
Как сделать это? Даем команду:
— в vi: s/^(1.)/12/g
— в emacs: ^(1.) заменяется на 12.
— в perl: perl -pe 's/^(1.)/${1}2/g' phonelist.txt.
Теперь новый список телефонов выглядит подобно этому:
Phone Name ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Kerry 534
...
Перл может обрабатывать переменные с номерами больше, чем от 1 до 9, поэтому 12 будет ссылаться на 12-ю переменную, которая, кстати, пустая. Для преодоления этого мы просто используем ${1}.
Теперь выравнивание в списке немного нарушено. Как вы можете это исправить? Вы должны просто проверить, есть ли пробел в 5-й позиции, и если есть, то вставить еще один:
— в vi: s/^(....) /1 /g
— в emacs: '^(....) ' replaced by '1 '
— в perl: perl -pe 's/^(....) /${1} /g' phonelist.txt
Теперь телефонный список будет выровненным.
Коллеги вручную подредактировали список и случайно вставили несколько пробелов в начале некоторых строк. Как мы можем удалить их? Следующая команда должна помочь:
— в vi: s/^ *// (здесь 2 пробела, т.к. мы не имеем +).
— в emacs: '^ +' заменяем пустой строкой.
— в perl: perl -pe 's/^ +//' phonelist.txt.
Вы пишите программу, и в ней у вас есть переменные temp и temporary. Теперь вы хотите заменить переменную temp переменной counter. Если вы просто замените строку temp на counter, то переменная temporary станет counterrary, что, видимо, не то, что вы хотите. Регулярные выражения могут сделать и это. Просто меняем temp([^o]) на counter1. Это значит temp без буквы o (альтернативным решением может быть использование границ, но мы не рассматриваем этот случай привязки шаблона).
Надеюсь, что эта статья вас заинтересовала. Теперь вы можете захотеть взглянуть в документацию вашего любимого редактора и изучить все подробности, так как есть еще много других специальных символов, таких, как, например, символы условий, типа "или", и символы границ слов, упоминаемые выше.
Успешного вам использвания регулярных выражений!
 
Автор: Unknown
 
Оригинал статьи: http://woweb.ru/publ/66-1-0-172