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 .baksed поймёт как скрипт.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