← Весь справочник

sed

Потоковый редактор — замена по регулярке, удаление и вставка строк, правка файлов на месте

sed читает текст построчно, применяет к каждой строке команды из скрипта и печатает результат. Чаще всего его используют для замены s/было/стало/, но он умеет удалять, вставлять и выбирать строки по номеру или шаблону. В песочнице — GNU sed 4.9.

Синтаксис

sed [опции] 'скрипт' [файл…]
sed [опции] -e 'команда1' -e 'команда2' [файл…]
sed [опции] -f скрипт.sed [файл…]

Как это работает: sed кладёт очередную строку (без \n) в буфер — pattern space, выполняет над ним по порядку все команды скрипта, печатает буфер (если нет -n) и берёт следующую строку. Команды в одном скрипте разделяются ; или переводом строки. Исходный файл не меняется, пока не указан -i.

Опции

ОпцияЧто делает
-nне печатать буфер автоматически — выводится только то, что напечатают p, P, = и т. п.
-e скриптдобавить команды; можно повторять
-f файлвзять команды из файла
-E (-r)расширенные регулярки: + ? | ( ) { } без обратных слэшей
-iправить файлы на месте
-i.bakправить на месте, сохранив исходник как файл.bak (суффикс пишется слитно)
--follow-symlinksс -i: править файл, на который указывает ссылка, а не заменять саму ссылку
-sсчитать файлы отдельными: $ и номера строк — внутри каждого файла (с -i включается само)
-zстроки разделены нулевым байтом, а не \n — так весь файл без нулей становится одной «строкой»
-uне буферизовать вывод (для tail -f | sed …)
--posixотключить расширения GNU
--debugпоказать, как выполняется скрипт
--sandboxзапретить команды e, r, w, работающие с файлами и оболочкой

Адреса

Адрес перед командой ограничивает строки, к которым она применяется.

АдресКакие строки
(нет)все
5 / $пятая / последняя
/рег/где есть совпадение; \%рег% — то же с другим разделителем; /рег/I — без регистра
2,5со 2-й по 5-ю
/начало/,/конец/от строки с начало до ближайшей следующей с конец включительно; диапазон может повторяться
5,$ / /рег/,$от 5-й (или от совпадения) до конца
0,/рег/от начала до первого совпадения, даже если оно в первой строке (GNU)
/рег/,+2строка с совпадением и ещё 2 после (GNU)
1~3каждая третья, начиная с первой (GNU)
адрес!все строки, кроме подходящих под адрес

Команды

КомандаЧто делает
s/рег/замена/флагизаменить совпадение (подробнее ниже)
dудалить буфер и сразу перейти к следующей строке
pнапечатать буфер (с -n — единственный вывод)
=напечатать номер строки
a текст / i текствставить строку после / перед текущей
c текстзаменить строку (или весь диапазон) текстом
y/abc/xyz/посимвольная замена, как tr
q / Qвыйти, напечатав / не печатая текущую строку; q5 — с кодом возврата 5
r файл / w файлвставить содержимое файла после строки / дописать строку в файл
n / Nзаменить буфер следующей строкой / дописать следующую строку в буфер через \n
h H g G xкопировать / дописать буфер в запасной (hold space), вернуть / дописать оттуда, обменять
{ …; … }группа команд под одним адресом

Команда s

Разделитель — любой символ сразу после s: s|/a|/b|, s#x#y#.

ЭлементЧто значит
& в заменевсё совпадение
\1 … \9группы из скобок (\( \) в BRE, ( ) с -E)
\n в заменеперевод строки
\U \L / \u \l / \Eдальше всё в верхнем / нижнем регистре, следующий символ в верхнем / нижнем, конец преобразования (GNU)
флаг gзаменить все вхождения в строке, а не только первое
флаг N (число)заменить только N-е вхождение; Ng — N-е и все после
флаг Iбез учёта регистра
флаг pнапечатать строку, если замена была (обычно с -n)
флаг w файлдописать изменённую строку в файл

Примеры

printf 'one\ntwo\nthree\nfour\nfive\n' > n.txt

# первое «o» в каждой строке; с g — все; только второе вхождение
sed 's/o/0/' n.txt
sed 's/o/0/g' n.txt
echo 'foo foo' | sed 's/o/0/2'

# заменить только в строках, где есть «t»
sed '/t/s/e/E/g' n.txt

# напечатать строки 2–4; строку с совпадением и одну после
sed -n '2,4p' n.txt
sed -n '/two/,+1p' n.txt

# удалить строки, начинающиеся с t; удалить пустые и из одних пробелов
sed '/^t/d' n.txt
printf 'a\n\n   \nb\n' | sed '/^[[:space:]]*$/d'

# всё, кроме строк с «o», — удалить
sed '/o/!d' n.txt

# другой разделитель, если в тексте много слэшей
echo '/usr/local/bin' | sed 's|/usr/local|/opt|'

# переставить части через группы; & — всё совпадение
echo 'key = value' | sed -E 's/^([a-z]+) = (.*)/\2=\1/'
echo 'abc' | sed 's/b/[&]/'

# регистр
echo 'hello world' | sed -E 's/\w+/\u&/g'
echo 'hello' | sed 's/.*/\U&/'

# закомментировать строку и раскомментировать обратно
echo 'option=1' | sed 's/^/# /'
echo '# option=1' | sed 's/^#[[:space:]]*//'

# вставить, заменить строку, номер строки
sed '2i --- before two ---' n.txt
sed '/three/c 3' n.txt
sed -n '/four/=' n.txt

# правка на месте с резервной копией; несколько команд
sed -i.bak -e '1i header' -e '$a footer' n.txt

# первые 3 строки и выход (не читая файл дальше)
sed 3q n.txt

# склеить все строки в одну через запятую
printf 'a\nb\nc\n' | sed -z 's/\n/,/g; s/,$/\n/'

# подставить переменную оболочки: двойные кавычки и разделитель, которого нет в значении
dir=/srv/data
echo 'path=old' | sed "s|old|$dir|"

Подводные камни

  • Без -E скобки и + — обычные символы. sed 's/(a+)/X/' ищет буквально (a+). Либо добавь -E, либо экранируй: \(a\+\).
  • Одинарные кавычки не пропускают переменные. sed 's/x/$var/' вставит текст $var. Используй двойные кавычки — и следи, чтобы $ и ` в самом скрипте не были съедены оболочкой.
  • Слэши в значении ломают команду. Если в подставляемой строке есть /, бери другой разделитель: s|…|…| или s#…#…#. Символы & и \ в значении тоже нужно экранировать.
  • -i без копии необратим. Сначала запусти без -i и посмотри вывод. Суффикс пишется слитно: -i.bak; -i .bak sed поймёт как скрипт .bak. На macOS (BSD sed) синтаксис другой: -i ''.
  • -i заменяет символическую ссылку обычным файлом, а исходный файл не трогает. Чтобы править цель ссылки, добавь --follow-symlinks.
  • -n + p. Без -n команда p напечатает строку дважды. А -n без p ничего не выведет.
  • sed работает по строкам: \n в шаблоне не встретится, пока ты сам не склеишь строки через N или -z.
  • Регулярки жадные. s/X.*X/-/ захватит от первого до последнего X в строке. Ленивых .*? в sed нет — используй класс-отрицание: X[^X]*X.
  • Диапазон /a/,/b/ ищет конец, начиная со следующей строки. Если b не найдено, диапазон длится до конца файла.

См. также

Регулярные выражения · grep · awk · tr