Потоковый редактор 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.