Потоковый редактор SED

Sed — лёгкий (бинарник весит всего 128 килобайт) и удобный инструмент обработки текста.

В этой статье я приведу несколько простых примеров использования sed и расскажу о его основных возможностях.

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

Формат команды sed

Команда sed имеет формат:

sed [ -n ] [ -e скрипт ] [ -f скрипт-файл ] [ файлы ]

Флаг -n подавляет вывод
-e — указывает на список инструкций, заданный в командной строке.
-f — указывает местонахождение файла-скрипта.

Формат команд редактирования

Скриптовый файл состоит из набора команд:

[ адрес [ , адрес ] ] команда [ аргументы ]

по одной в каждой строке.
Адреса это либо номера строк, либо специальные символы, либо регулярное выражение:

$ — последняя строка
начало~N — Каждая N-я строка, начиная с номера начало
/регулярное_выражение/ — строки, попадающие под регулярное_выражение
Примеры:

1~2 — Каждая вторая строка
/REGEXP/ — все строки, в которых встречается /REGEXP/
10,20 — строки с 10-й по 20-ю
10,+10 — строки с 10-й по 20-ю
5,~N — строки начиная с 5-й и до первой, кратной N
5,/REGEXP/ — строки, содержащие /REGEXP/, после 5-й(не включая 5-ю)
  • Если адрес не указан, обрабатываются все строки.
  • Если указан один адрес — обрабатывается соответствующая строка
  • Если указаны два адреса, то выбираются строки в заданном интервале.
  • !команда — выполняется команда, для строк, которые небыли выбраны по адресам.

Основные команды

Рассмотрим основные команды:

[адрес] a текст — добавить новую строку с текстом после указанной строки

$ cat sed_test sed_test_1 11111 sed_test_2 22222 sed_test_3 33333 $ sed -e '2 a new_line' sed_test sed_test_1 11111 sed_test_2 22222 new_line sed_test_3 33333

[адрес [, адрес]] c текст — Удаляет выбранные строки и заменяет их на текст

$ sed -e '2 с new_line' sed_test sed_test_1 11111 new_line sed_test_3 33333 $ sed -e '/3/ с new_line' sed_test sed_test_1 11111 sed_test_2 22222 new_line

[адрес [, адрес]] d — Удаляет указанные строки.

$ sed -e '2 d' sed_test sed_test_1 11111 sed_test_3 33333 $ sed -e '2!d' sed_test sed_test_2 22222

[адрес] i текст — Вставить текст на место указанной строки.

$ sed -e '2 i new_line' sed_test sed_test_1 11111 new_text sed_test_2 22222 sed_test_3 33333

[адрес [, адрес]] p (с флагом -n) выводит найденные строки.

$ sed -ne '2p' sed_test sed_test_2 22222

[адрес] q — выход из sed.

[адрес [, адрес]] r файл — Читает файл и выдает его содержание на выход.

[адрес [, адрес]] s/регулярное_выражение/замена/флаги — Заменяет регулярное_выражение на замена-у с учётом флагов:

  • g — во всей строке
  • i — без учёта регистра
  • p — выводить результат замены
$ sed -ne 's/t/T/g' sed_test sed_TesT_1 11111 sed_TesT_2 22222 sed_TesT_3 33333 $ sed -e 's/[0-9]/d/g' sed_test sed_test_d ddddd sed_test_d ddddd sed_test_d ddddd

[адрес [, адрес]] y/строка1/строка2/ — Заменяет все вхождения символов в строке1 соответсвующими символами из строки2. Длины строк должны быть одинаковыми.

$ sed -ne 'y/est/EST/g' sed_test SEd_TEST_1 11111 SEd_TEST_2 22222 SEd_TEST_3 33333

[адрес [, адрес]] { команды } — скобки группируют команды
[адрес] = — Выдаёт номера строк

Метки

: метка — сопоставить группе команд метку
b метка — переход к команде, обозначенной меткой метка, если метка отсутствует, то переход в конец командного файла.

t метка — переход к команде, обозначенной меткой метка только после удачной замены с помощью команды s///

Цикл выполнения

sed работает с двумя буферами данных: основным и вспомогательным. Изначально оба буфера пусты.
Работа с этими буферами осуществляется при помощи команд:\\`h', `H', `x', `g', `G' `D' h — Заменить содержимое вспомогательного буфера содержимым основного
H — Добавить новую строку к вспомогательному буферу и затем добавить содержимое основного буфера к содержимому вспомогательного
x — Поменять содержимое обоих буферов местами
g — Заменить содержимое основного буфера содержимым вспомогательного
G — Добавить новую строку к основному буферу и затем добавить содержимое вспомогательного буфера к содержимому основного
D — Удалить текст основного буфера до следующего символа перевода строки
N — Добавить новую строку к основному буферу, затем добавить туда следующую обрабатываемую строку
P — Вывести содержимое основного буфера до следующего символа перевода строки.

Более сложные примеры

Следующий скрипт меняет местами строки файла (первые строки становятся последними и наоборот)

$ cat tac.sed #!/usr/bin/sed -nf # начиная со второй строки, содержимое буфера (который уже содержит # все предыдущие строки) добавляется к текущей строке. 1! G # при достижении последней строки - печатаем $ p # Заносим данные в буфер опять h sed -nf tac.sed sed_test sed_test_3 33333 sed_test_2 22222 sed_test_1 11111

Считаем строки файла (выводим номер последней строки)

$ cat count.sed #!/usr/bin/sed -nf $=

результат

$ sed -nf count.sed sed_test 3

Обращение строк

$ cat revers.sed #!/usr/bin/sed -f # пропускаем строки из одной буквы /../! b # Переворачиваем строку. Добавляем по пустой строке перед и после текущей. s/^.*$/\ &\ / # Переносим первый символ в конец # цикл работает пока в средней строке есть символы. tx :x s/\(\\n.\)\(.*\)\(.\\n\)/\\3\\2\\1/ tx #удаляем лишние переносы строк s/\\n//g

Этот скрипт перемещает две буквы за раз.

$ sed -f revers.sed sed_test 11111 1_tset_des 22222 2_tset_des 33333 3_tset_des

Дополнительная информация

Подробнее о формате sed-скриптов можно узнать, прочитав мануал man sed или техническую документацию info sed.