Команда s, вне всяких сомнений, используется намного чаще других команд редактирования. Далее мы рассмотрим только часть ее возможностей, выполняя редактирование нашего файла distros.txt. Мы уже говорили, что поле даты в distros.txt хранит информацию не в самом «дружественном» для компьютеров виде. Здесь даты записаны в формате ММ/ДД/ГГГГ, однако гораздо удобнее (для сортировки) было бы, если бы даты были записаны в формате ГГГГ-ММ-ДД. Замена представления дат вручную — довольно утомительное занятие и чревато ошибками, но с помощью sed ту же замену можно выполнить в одно действие:

[me@linuxbox ~]$ sed 's/\([0-9]\{2\}\)\/\([0-9]\{2\}\)\/\([0-9]\{4\}\)$/\3-\1-\2/' distros.txt

SUSE             10.2    2006-12-07

Fedora           10      2008-11-25

SUSE             11.0    2008-06-19

Ubuntu           8.04    2008-04-24

Fedora           8       2007-11-08

SUSE             10.3    2007-10-04

Ubuntu           6.10    2006-10-26

Fedora           7       2007-05-31

Ubuntu           7.10    2007-10-18

Ubuntu           7.04    2007-04-19

SUSE             10.1    2006-05-11

Fedora           6       2006-10-24

Fedora           9       2008-05-13

Ubuntu           6.06    2006-06-01

Ubuntu           8.10    2008-10-30

Fedora           5       2006-03-20

Прекрасный результат! Правда, команда выглядит устрашающе, но она работает. За один шаг мы изменили представление дат во всем файле. Этот пример также наглядно показывает, почему про регулярные выражения иногда в шутку говорят «только для записи». Мы можем писать их, но прочитать их порой никак не получается. Прежде чем сбежать от этой устрашающей команды, давайте посмотрим, как она была сконструирована. Во-первых, как мы уже знаем, эта команда имеет следующую структуру:

sed 's/регулярное_выражение/строка_замены/' distros.txt

Теперь разберем регулярное выражение, отыскивающее даты. Так как даты имеют формат ММ/ДД/ГГГГ и находятся в конце строки, найти их можно с помощью следующего выражения:

[0-9]{2}/[0-9]{2}/[0-9]{4}$

которому соответствуют две цифры, слеш, две цифры, слеш, четыре цифры и конец строки. Так, с регулярным выражением разобрались, а что со строкой замены? Чтобы описать ее, нам необходимо познакомиться с новой для нас особенностью регулярных выражений, которую можно использовать в некоторых приложениях, поддерживающих BRE. Эта особенность называется обратные ссылки, и действует она так: если в строке замены присутствует последовательность \n, где n — число от одного до девяти, эта последовательность будет ссылаться на совпадение с соответствующим подвыражением в предшествующем регулярном выражении. Чтобы создать подвыражение, достаточно просто заключить часть регулярного выражения в круглые скобки, например:

([0-9]{2})/([0-9]{2})/([0-9]{4})$

Теперь у нас есть три подвыражения. Первому соответствует месяц, второму — число месяца и третьему — год. Соответственно строку замены можно выразить так:

\3-\1-\2

что даст нам в результате такую последовательность: год, дефис, месяц, дефис, число месяца.

Теперь наша команда приобрела следующий вид:

sed 's/([0-9]{2})/([0-9]{2})/([0-9]{4})$/\3-\1-\2/' distros.txt

Но остались две проблемы. Первая: дополнительные слеши в регулярном выражении запутают программу sed, когда она попытается интерпретировать команду s. Вторая: так как по умолчанию sed принимает только простые регулярные выражения, некоторые символы в нашем регулярном выражении будут интерпретироваться как литералы, а не как метасимволы. Мы решим обе ­проблемы, применив символы обратного слеша для экранирования нужных символов:

sed 's/\([0-9]\{2\}\)\/\([0-9]\{2\}\)\/\([0-9]\{4\}\)$/\3-\1-\2/' distros.txt

И дело в шляпе!

Другая особенность команды s — возможность использования дополнительных флагов вслед за строкой замены. Наиболее примечательным из них является флаг g, который требует от sed применить поиск с заменой к строке глобально (globally), а не только к первому найденному совпадению, как это делается по умолчанию.

Например:

[me@linuxbox ~]$ echo "aaabbbccc" | sed 's/b/B/'

aaaBbbccc

Как видите, замена была выполнена только для первого вхождения буквы b, а остальные остались нетронутыми. Добавив флаг g, можно изменить все вхождения:

[me@linuxbox ~]$ echo "aaabbbccc" | sed 's/b/B/g'

aaaBBBccc

До сих пор мы передавали команды программе sed только по одной и только в командной строке. Однако существует возможность создавать более сложные коман­ды в файлах сценариев и передавать эти сценарии с помощью параметра -f. Для демонстрации создадим с помощью sed отчет на основе нашего файла distros.txt. Отчет будет содержать заголовок вверху, измененные даты и названия дистрибутивов будут преобразованы в верхний регистр. Для этого нам понадобится написать сценарий, поэтому запустите текстовый редактор и введите следующие строки:

Перейти на страницу:

Похожие книги