Что такое addresses в sed
Каждая команда sed может быть ограничена адресами: к каким строкам её применять. Формат:
[ADDR][,ADDR2] COMMAND
- Без адресов — команда применяется ко всем строкам
- Один адрес — только к строкам, соответствующим адресу
- Два адреса через запятую — диапазон с первой по вторую
$ sed '3d' file # удалить строку 3
$ sed '1,5d' file # удалить строки 1-5
$ sed '/pattern/d' file # удалить строки, совпадающие с pattern
$ sed '10,$d' file # удалить строки с 10-й до конца ($ = last line)
$ sed '/^#/d' file # удалить все комментарии
$ sed '$!d' file # удалить все КРОМЕ последней (! инвертирует address)
Виды адресов
От line number до regex.
Команда d: delete
Удаляет строку из output. Самая частая команда с адресами.
# Удалить первую строку (header CSV)
$ sed '1d' data.csv
# Удалить строки 1-5
$ sed '1,5d' file
# Удалить все пустые строки
$ sed '/^$/d' file
# Удалить все комментарии (# в начале)
$ sed '/^#/d' /etc/ssh/sshd_config
# Удалить comments и empty lines одной командой
$ sed -e '/^#/d' -e '/^$/d' /etc/ssh/sshd_config
# или альтернативный синтаксис:
$ sed '/^#\|^$/d' /etc/ssh/sshd_config # BRE с \|
$ sed -E '/^(#|$)/d' /etc/ssh/sshd_config # ERE
d — это «не выводи эту строку и переходи к следующей». Внутри sed это команда «пропусти оставшиеся команды для этой строки», но в pipeline эффект — удаление.
Команда p и -n: print only matching
$ sed '/ERROR/p' file
# Странно: выводит ВСЕ строки, и ERROR-строки ДВАЖДЫ
Почему? sed по умолчанию выводит каждую обработанную строку. Команда p явно дублирует output. Чтобы получить только matching:
$ sed -n '/ERROR/p' file
# -n (quiet) выключает default print
# теперь только команды p реально выводят
-n и p всегда работают парой. Это эквивалентно grep ERROR file, но sed может делать substitution в одной команде:
$ sed -n 's/ERROR.*dag_id=\([a-z_]*\).*/\1/p' app.log
# Выводит только dag_id из строк с ERROR — substitution + p в одной команде
p после s/.../.../ означает: «если substitution произошёл — print». Это мощный idiom: matching + transform + output одной командой.
Команда q: quit
$ sed '10q' file
# Вывести первые 10 строк и завершиться
# Эквивалент head -n 10, но быстрее на больших файлах:
# sed читает до 10-й строки и выходит, head может буферизовать больше
# Вывести строки от начала до первой ERROR
$ sed '/ERROR/q' app.log
# (включая саму строку с ERROR)
DE-сценарии
1. Очистка конфига (без комментариев и пустых строк)
$ sed '/^[[:space:]]*#/d; /^[[:space:]]*$/d' /etc/airflow/airflow.cfg
[[:space:]]* — учесть пробелы/табы перед # или в пустой строке. ; разделяет несколько команд внутри одного sed-вызова.
2. Извлечь строки между двумя маркерами
# Извлечь Python-блок между BEGIN_CODE и END_CODE
$ sed -n '/BEGIN_CODE/,/END_CODE/p' notebook.md
/start/,/end/ — диапазон по regex. Полезно для:
- Извлечения секций конфигов
- Очистки markdown-кодоблоков
- Парсинга structured logs (где stack-trace между маркерами)
3. Удалить header без tail -n +2
$ sed '1d' data.csv
# Эквивалент tail -n +2 data.csv, но работает в pipeline без extra процесса
4. Замена в конкретной строке
# Заменить slug в 1-й строке Markdown header
$ sed '1s/Old Title/New Title/' README.md
Адрес + s-команда: substitution применяется только к строкам, попадающим в адрес.
# Закомментировать строки 10-20
$ sed '10,20s/^/# /' file
5. Удалить trailing whitespace во всём файле
$ sed -i 's/[[:space:]]*$//' file.py
6. Преобразовать CRLF -> LF (Windows -> Unix)
$ sed -i 's/\r$//' file
# \r = CR (Windows line ending CRLF = \r\n; на Unix только \n)
Несколько команд в одном вызове
Три способа:
# 1. Через -e
$ sed -e '1d' -e 's/foo/bar/g' -e '/^$/d' file
# 2. Через ; внутри 'программы'
$ sed '1d; s/foo/bar/g; /^$/d' file
# 3. Через \n (новые строки)
$ sed '1d
s/foo/bar/g
/^$/d' file
Все эквивалентны. На производстве -e или ; — наиболее читаемо.
Sed scripts из файла
Большие sed-программы пишут в файл и подключают через -f:
# /tmp/clean.sed
1d
s/[[:space:]]*$//
/^[[:space:]]*#/d
/^[[:space:]]*$/d
$ sed -f /tmp/clean.sed input.txt
Удобно для reusable transformation pipelines.
Sed hold space — для продвинутых
Sed имеет два буфера: pattern space (текущая строка, default) и hold space (вторичный буфер). Команды h, H (copy to hold), g, G (copy from hold) позволяют делать multi-line операции:
# Reverse порядок строк (tac равен этому):
$ sed '1!G;h;$!d' file
Это «sed magic». Для DE редко нужно — лучше переключиться на awk или perl, которые имеют переменные.
Попробуй сам
- Удалить первую строку:
printf "header\na\nb\nc\n" | sed '1d' # -> a, b, c - Удалить пустые строки:
printf "a\n\nb\n\nc\n" | sed '/^$/d' - Извлечь диапазон:
seq 1 20 | sed -n '5,10p' # -> 5, 6, 7, 8, 9, 10 - Замена только в первой строке:
printf "title\ntitle\ntitle\n" | sed '1s/title/MAIN/' - Удалить комментарии и пустые в /etc/ssh/sshd_config:
sed '/^#/d; /^$/d' /etc/ssh/sshd_config | head
macOS-различия
- BSD sed на macOS:
N,$(диапазон до конца) — работает/regex/d— работает\b,\d,\s— НЕ поддерживаются, используй POSIX-классы ([[:alnum:]])N~step(каждая N-я) — не поддерживается, GNU-only-iтребует empty arg (см. урок 1)
- Альтернативный delimiter
\@regex@d— может потребовать backslash перед делимитером на BSD. - Для cross-platform —
perl -ne 'next if /^#/; print'(perl на обеих платформах одинаков).
Главное
- Адреса:
N(line),N,M(range),$(last),/regex/,/start/,/end/. !инвертирует адрес:'$!d'= «удалить все кроме последней».d— delete (skip output).p— print explicitly.q— quit after match.-n(quiet) выключает default autoprint; нужен сpдля grep-эффекта.- Несколько команд:
-e CMD -e CMDили'CMD1; CMD2'. - Большие программы — в файл, подключать через
sed -f file.sed. - Sed hold space — для multi-line магии (используется редко, лучше awk/perl).