Еще несколько слов о sed

В связи с запуском собственного jabber-бота я решил детально изучить потоковый редактор sed. С его помощью можно править тексты сравнительно короткими консольными командами, что, собственно, и позволяет делать бот. Учебников по sed в Интернете полно. Выбрал Sed — An Introduction and Tutorial by Bruce Barnett. Во-первых, потому что он обновился буквально месяц назад (sed хотя и имеет почти 40-летнюю историю, но до сих пор весьма актуален). Во-вторых, текст этот очень адекватный, с шутками-прибаутками, читается легко. В-третьих, материала в нем в самый раз. За 5 минут, конечно, не одолеешь, но и добраться до конца захода за 2-3 вполне возможно. В данном топике я хочу зафиксировать для себя почерпнутые в упомянутом учебнике знания, в форме, которая может и еще кому-нибудь из русскоязычных читателей покажется удобной.

Автор учебника Брюс Барнет начинает свое повествование о sed с тезиса о том, что базовые возможности этой программы многим уже хорошо известны. Программисты и администраторы средней руки вполне себе владеют командами типа

echo day | sed s/day/night/ 


Это правильно: раз уж человек искал в Сети мануал для углубленного изучения sed, то нечего его кормить избитыми истинами. Но что это? Так славно начав, автор опять разжевывает для нас регулярные выражения, инструкции с поиском и заменой, да еще и «сдабривая» их труднозапоминаемыми ключами. Мне кажется, материал лучше излагать в другом порядке.

Во-первых, давайте временно абстрагируемся от того факта, что у sed есть масса ключей, влияющих на его поведение. Будем рассматривать только возможности выражений, интерпретируемых редактором. Во-вторых, нужно, наконец, отойти от самой эффектной, но далеко не единственной команды sed — s, позволяющей выполнять замену в пропускаемых через него строках. Вот с этими оговорками попробую пересказать то, что усвоил.

Итак, sed — текстовый редактор. Только изменяет он текст не в интерактивном режиме, а пропуская его через себя, анализируя и меняя в соответствии с переданным ему алгоритмом.



Аббревиатура Sed означает Stream editor, т.е. потоковый редактор. Поэтому здесь нет таких понятий, как «открыть файл», «сохранить файл» и т.д. С другой стороны, никто не мешает превратить файл в поток и пропустить через sed:

cat foo | sed 's/day/night/'


Это значит заменить в потоке, созданном из файла foo, слово day на слово night.

Естественно, создатели sed живут отнюдь не в вакууме и прекрасно знают, что люди прежде всего хотят редактировать файлы, поэтому имя файла можно передать в качестве аргумента:

sed 's/day/night/' foo


И все-таки нужно постоянно держать в голове то обстоятельство, что обрабатывается именно поток.

Второе, что нужно иметь в виду — поток обрабатывается построчно. Sed считывает последовательности символов порциями до ближайшего разрыва строки (в программировании обозначается как \n или \r\n в Windows-системах) и решает что делать со считанной строкой в соответствии с переданными ему командами.

Что же это за команды такие? Это последовательности символов, передаваемые программе sed, в соответствии с которыми он выполняет действия, присущие любому текстовому редактору: правит строки, добавляет их, удаляет и т.п. Команды указываются строчными буквами латинского алфавита. Самая известная команда sed — s. Применяется для поиска и замены по шаблону. После нее обычно идут заключенные в слэши regex-последовательности. Однако не менее эффективны и другие команды: d — удалить (delete), a — добавить (append) и т.д.

Привычные большинстру пользователей ПК текстовые редакторы работают в режиме полуавтомата: пользователь с помощью клавиатуры и мыши постоянно перемещается по тексту, выделяет его фрагменты, удаляет, вставляет, сохраняет и т.п. Sed же работает в режиме автомата — получает задание (те самые команды), получает входной поток и выдает выходной. Вмешаться в его работу «на ходу» невозможно. Поэтому прежде всего sed должен знать какие строки подвергать обработке. Вот здесь как раз мы и сталкиваемся с ущербностью большинства учебных пособий по sed, делающих упор на такие примеры, как

echo day | sed 's/day/night/' 


Такое использование sed — всего лишь частный случай. Здесь не сказано, какие строки обрабатывать и обрабатываются все подряд. Не зная этого, плохо подготовленные пользователи sed (таковым пару дней назад был и я сам) городят умопомрачительные regex-выражения, путаются в них, бросают и всё кончается тем, что «sed — фигня, буду лучше править в vim'е». На самом деле нужно иногда просто читать мануалы ограничить диапазон обрабатываемых строк, и команды sed упростятся в разы. Диапазон строк ограничивается числами в начале выражения, например,

sed '5,10 s/day/night/' calendar.txt


Это значит заменить в потоке, полученном из файла calendar.txt слово day на слово night в строках с 5 по 10.

sed '5,10 d' calendar.txt


— в потоке, полученном из файла calendar.txt удалить строки с 5 по 10.

Указать строки, подлежащие обработке, можно не по номерам, а шаблонами, например

sed '/freeday/,/sunday/ d' calendar.txt


— в потоке, полученном из файла calendar.txt начинать удалять строки с той, где впервые встретится слово freeday и прекратить удалять, как только встретится слово sunday.

Если применить не простую и понятную команду d (delete), а s, аргументы которой сами по себе бывают весьма сложными, то как раз и получится та ужасная каша из слэшей, которая у многих отбивает желание изучать sed:

sed '/freeday/,/sunday/ s/day/night/' calendar.txt


На самом же деле всё просто: в потоке, полученном из файла calendar.txt начинать менять слово day на слово night в строках, начиная с той, где впервые встретится freeday и прекратить замены как только встретится слово /sunday/.

Таким образом, выражение, передаваемое sed, содержит диапазон и команду, которую нужно выполнять в этом диапазоне. После команды могут идти ее аргументы. Например, у d аргументов нет (она удаляет строки, какие уж тут аргументы). А вот после s требуется указать регулярные выражения для вставки и замены, после a (append) — текст, который вставляется, например,

sed '1 a Yo!'


— вставить после первой строки строку, содержащую «Yo!».

Давайте, наконец, выйдем за рамки очевидных команд s (search/replace), a (append) и d (delete) и перечислим еще несколько из тех, понимание которых требует минимальных усилий, т.к. есть и довольно заковыристые (например p), о которые можно споткнуться и так и не дочитать топик до конца.

Команда i (insert) — вставить строку. Отличается от a (append) лишь тем, что добавляет строку не после указанной позиции, а перед ней.

Команда c (change) — заменяет строку на свой аргумент

sed '1 c Yo!'


— заменить 1-ю строку на 'Yo!'

Команда y — меняет один набор символов на другой

sed 'y/abcdef/ABCDEF/'


— заменить строчные буквы с a по z на соответствующие заглавные.

Команда w (write) — записать указанные строки в файл, имя которого указано в качестве аргумента.

sed '1 w firstline.txt'


— записать первую строку анализируемого потока в файл firstline.txt.

Команда r (read) — вставить текст, прочитанный из файла.

sed '1 r firstline.txt'


— после первой строки вставить текст, считанный из файла firstline.txt.

Команда q (quit) — прекратить обработку.

sed '10 q'


— после 10-q строки прекратить работу sed, например, в связи с тем, что дальше в потоке не предвидится ничего интересного.

Надеюсь, до этого места было дочитать не трудно. Но всё хорошее быстро кончается: остальные возможности sed не так легко усвоить, как перечисленные, а посему пусть каждый сам решит на что ему обратить внимание: кто-то, возможно, захочет в совершенстве изучить регулярные выражения, кто-то — ключи sed, на порядок расширяющие его возможности, кто-то — в оригинале прочитать статью Брюса Барнета (у этого автора есть хорошие материалы и о других консольных инструментах). Главное — чтобы в голове не было каши, которая легко получается, если пытаться sed и подобные ему программы «брать наскоком». По себе знаю .

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.