([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. Отчет будет содержать заголовок вверху, измененные даты и названия дистрибутивов будут преобразованы в верхний регистр. Для этого нам понадобится написать сценарий, поэтому запустите текстовый редактор и введите следующие строки:
# Сценарий для sed, создающий отчет о дистрибутивах Linux
1 i\
\
Linux Distributions Report\
s/\([0-9]\{2\}\)\/\([0-9]\{2\}\)\/\([0-9]\{4\}\)$/\3-\1-\2/
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
Сохраните сценарий в файл с именем distros.sed и запустите его:
[me@linuxbox ~]$ sed -f distros.sed distros.txt
Linux Distributions Report
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
Как видите, сценарий выдал желаемый результат, но как он это сделал? Давайте вернемся еще раз к нашему сценарию. Выведем его с помощью программы cat так, чтобы она пронумеровала строки.
[me@linuxbox ~]$ cat -n distros.sed
1 # Сценарий для sed, создающий отчет о дистрибутивах Linux
2
3 1 i\
4 \
5 Linux Distributions Report\
6
7 s/\([0-9]\{2\}\)\/\([0-9]\{2\}\)\/\([0-9]\{4\}\)$/\3-\1-\2/
8 y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
Строка с номером 1 — это комментарий. Так же как во многих конфигурационных файлах и языках программирования, широко используемых в Linux, комментарии начинаются с символа #, за которым следует пояснительный текст. Комментарии можно помещать в сценарии в любое место (только не в сами команды), и они, безусловно, полезны для всех, кто хочет выяснить особенности работы сценария или сопровождать его.
Строка 2 — это пустая строка. Так же как комментарии, мы можем добавлять пустые строки для удобочитаемости.
Многие команды sed поддерживают адресацию строк. Адреса используются, чтобы определить, к каким строкам во входном потоке применяется операция. Адреса могут выражаться в форме простых номеров строк, диапазонов номеров и специального номера $, соответствующего последней входной строке.
В строках с 3-й по 6-ю содержится текст, который должен быть вставлен по адресу 1, в первую входную строку. Команда i, сопровождаемая последовательностью из обратного слеша и перевода строки, производит экранированный символ перевода, или то, что мы называем символом продолжения строки. Эта последовательность используется во многих случаях, в том числе и в сценариях на языке командной оболочки, позволяя встраивать символ перевода строки в поток текста так, чтобы он не воспринимался интерпретатором (в данном случае программой sed) как конец строки. Команда i, а также команда a (добавления текста в конец) и команда c (замены текста), могут располагаться в нескольких строках текста, при условии, что каждая из них, кроме последней, будет завершаться символом продолжения строки. Шестая строка в нашем сценарии фактически завершает вставляемый текст и заканчивается уже не символом продолжения строки, а простым переводом строки, сообщая о завершении команды i.
Читать дальше