Потоковый редактор 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-й и до первой, кратной N5,/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/%$@~*!G4;:%#`.*$/\
&\
/

# Переносим первый символ в конец
# цикл работает пока в средней строке есть символы.
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.