GNU sed


GNU sed

GNU sed, stream editor — потоковый редактор. Уникальная утилита с двумя буферами: основным (pattern space) и вспомогательным (hold space); а также множеством однобуквенных команд для манипуляции этими буферами.

Здесь приведён краткий обзор этой исключительно прекрасной в своей сути утилиты. Десятикратно более подробный и точно более полный и честный, но требующий времени на чтение мануал: GNU sed Manual

Основы sed

  • Потоковая обработка: sed читает входные данные построчно, обрабатывает их согласно заданным командам и выводит результат. Как можно догадаться в качестве потока можно использовать и стандартный поток ввода и обычный файл, что весьма удобно.
  • Работа с буферами: для работы sed использует два основных буфера — буфер шаблонов (pattern space) и холд-буфер (hold space), между которыми можно обмениваться данными.
  • Однобуквенные команды: ещё в sed есть несколько десятков однобуквенных команд, которые можно комбинировать в скрипты и с помощью которых можно творить чудеса.

Как устроены скрипты для sed

Программа sed состоит из одной или нескольких команд sed, передаваемых с помощью опций -e, -f, --expression и --file или первого неопционального аргумента, если эти опции не используются.

Под программой sed будем подразумевать конкатенацию всех скриптов и файлов-скриптов в порядке передачи.

Команды sed следуют этому синтаксису:

[addr]X[options]

Где X - это однобуквенная команда sed. [addr] - необязательный адрес строки. Если [addr] указан, команда X будет выполнена только для соответствующих строк. [addr] может быть одним номером строки, регулярным выражением или диапазоном строк. Дополнительные [options] используются для некоторых команд sed.


Как устроены скрипты для sed

Например, следующая команда удаляет строки с 30 по 35:

sed '30,35d' input.txt > output.txt

Следующий пример печатает весь ввод до строки, начинающейся со слова «foo». Если такая строка найдена, sed завершится с кодом 42. Если строка не найдена (и не произошло других ошибок), sed завершится с кодом 0:

sed '/^foo/q42' input.txt > output.txt

Как устроены скрипты для sed

Команды в скрипте или файле скрипта могут разделяться точкой с запятой (;) или символами новой строки (ASCII 10).

Несколько скриптов можно указать с помощью опций -e или -f.

Следующие примеры эквивалентны - они выполняют две операции sed: удаление любых строк, соответствующих регулярному выражению /^foo/, и замену всех вхождений строки «hello» на «world»:

sed '/^foo/d ; s/hello/world/' input.txt > output.txt

sed -e '/^foo/d' -e 's/hello/world/' input.txt > output.txt

echo '/^foo/d' > script.sed
echo 's/hello/world/' >> script.sed 
sed -f script.sed input.txt > output.txt

echo 's/hello/world/' > script2.sed
sed -e '/^foo/d' -f script2.sed input.txt > output.txt

Как передавать команды в sed

Список команд

sed -e '1d' -e '$d' file.txt  # Удалить первую и последнюю строки


Чтение команд из файла

sed -f script.sed 


Исполнение скрипта

sed позволяет писать и выполнять более сложные скрипты для обработки текста.

Да, как и на любом другом языке просто указываем shebang:

#!/bin/sed -f
s/foo/bar/

Адресация

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

  • n: Применить команду к n-й строке.
  • $: Применить команду к последней строке.
  • /pattern/: Применить команду к строкам, соответствующим шаблону.
  • n,m: Применить команду к диапазону строк от n до m.
  • /start/,/end/: Применить команду к диапазону между двумя шаблонами.
  • Перекрестная адресация:
    sed '3,/pattern/s/old/new/' file.txt  # Заменяет 'old' на 'new' начиная с 3-й строки до строки с 'pattern'
  • Использование метасимволов:
    sed '0~2d' file.txt  # Удаляет каждую вторую строку, начиная с первой

Буферы

  • h: Копировать шаблон в холд-буфер.
  • H: Добавить шаблон к холд-буферу.
  • g: Копировать холд-буфер в шаблон.
  • G: Добавить холд-буфер к шаблону.
  • x: Обменять шаблон и холд-буфер.


Ввод-Вывод

  • p: Печатать шаблон.
  • n: Прочитать следующую строку и печатать.
  • d: Удалить шаблон и начать следующий цикл.
  • q: Выйти из sed.
  • r file: Читать содержимое файла.
  • w file: Записать шаблон в файл.
  • a\text: Добавить текст после строки.
  • i\text: Вставить текст перед строкой.
  • c\text: Заменить строку текстом.

Редактирование

  • s/pattern/replacement/: Заменить шаблон.
  • y/source/dest/: Транслитерировать символы.
  • =: Печатать номер строки.


Расширенные Команды

  • !: Применить команду к строкам, не соответствующим шаблону.
  • {}: Группировать команды.
  • :: Установить метку для перехода.
  • b label: Перейти к метке.
  • t label: Перейти к метке, если была выполнена замена.
  • N: Добавить следующую строку к шаблону.
  • P: Печатать первую часть шаблона до символа новой строки.
  • D: Удалить первую часть шаблона до символа новой строки.

Простые примеры

  • Примеры адресации:
    sed -n '1,5p' file.txt  # Вывести строки с 1 по 5

  • Добавление, удаление и замена текста:
    sed 's/old/new/g' file.txt  # Заменить 'old' на 'new' во всем файле

  • Многострочное удаление:
    sed '/^$/,/^$/d' file.txt  # Удалить пустые строки

Сложный пример 1: Переворачивание Текста

sed -re '1!G;h;$!d' forward.txt > backward.txt

Описание:

  • 1!G: Для каждой строки, кроме первой, добавляет содержимое холд-буфера в конец шаблона.
  • h: Копирует шаблон в холд-буфер.
  • $!d: Удаляет шаблон для всех строк, кроме последней.

Результат: Строки файла forward.txt записываются в обратном порядке в backward.txt.


Сложный пример 2: Инкремент Чисел

#!/usr/bin/sed -f
:d; s/9\(_*\)$/_\1/; td
s/^\(_*\)$/1\1/; tn
s/8\(_*\)$/9\1/; tn
s/6\(_*\)$/7\1/; tn # что тут происходит??? 
s/5\(_*\)$/6\1/; tn # 
s/4\(_*\)$/5\1/; tn 
s/3\(_*\)$/4\1/; tn 
s/2\(_*\)$/3\1/; tn
s/0\(_*\)$/1\1/; tn
:n
y/_/0/

Описание:

  • :d; s/9\(_*\)$/_\1/; td: Заменяет все 9 на _ справа налево.
  • s/^\(_*\)$/1\1/; tn: Добавляет 1 в начало, если строка состоит только из _.
  • s/[0-8]\(_*\)$/nextDigit\1/; tn: Заменяет каждую цифру на следующую.
  • y/_/0/: Заменяет все _ на 0.

Результат: Инкрементирует числа в файле.


Сложный пример 3: Удаление Повторяющихся Строк

sed '$!N; /^\(.*\)\n\1$/!P; D'

Описание:

  • $!N: Добавляет следующую строку к шаблону, если это не последняя строка.
  • /^\(.*\)\n\1$/!P: Печатает шаблон, если две строки в нем не одинаковы.
  • D: Удаляет первую часть шаблона до новой строки.

Результат: Удаляет соседние дубликаты строк.


Сложный пример 4: Преобразование Markdown заголовков в HTML

sed -e 's/^# \(.*\)$/\<h1\>\1\<\/h1\>/' -e 's/^## \(.*\)$/\<h2\>\1\<\/h2\>/'

Описание:

  • s/^# \(.*\)$/\<h1\>\1\<\/h1\>/: Заменяет строки, начинающиеся с #, на теги <h1>.
  • s/^## \(.*\)$/\<h2\>\1\<\/h2\>/: Заменяет строки, начинающиеся с ##, на теги <h2>.

Результат: Преобразует Markdown заголовки в HTML.


Регулярные выражения в sed

  • Базовые и расширенные регулярные выражения: sed поддерживает оба типа регулярных выражений, что позволяет выполнять сложные поисковые запросы.
  • Примеры шаблонов поиска:
    sed -n '/^root/p' /etc/passwd  # Найти строки, начинающиеся с 'root'

Повторение функциональности некоторых утилит с помощью sed

Здесь

  • tac: переворачивает строки файлов
  • cat -n: нумерует строки
  • cat -b: нумерует непустые строки
  • wc -c: считает количество символов
  • wc -w: счиатет количество слов
  • wc -l: считает количество строк
  • head: печатает первые n строк
  • tail: печатает последние n строк
  • uniq: удаляет повторяющиеся соседние строки
  • uniq -d: печатает повторяющиеся строки
  • uniq -u: удаляет повторяющиеся соседние строки, но выводит только уникальные, т.е. те, которые в изначальном вводе были в единственном числе
  • cat -s: сжатие пустых строк