sed¶
Команда SED — Полное руководство по потоковому редактору в Linux¶
Что такое SED?¶
SED (Stream EDitor) — консольная утилита для редактирования текстовых потоков. Разработана для Unix, широко портирована на все платформы. Название отражает суть: SED читает поток текста построчно и применяет к каждой строке заданную микропрограмму.
Принцип работы:
Типичные задачи: - Замена подстрок по регулярным выражениям - Удаление, вставка, изменение строк - Вывод фрагментов файла - Автоматизированная правка конфигурационных файлов - Построение простых текстовых препроцессоров
💡 Правило выбора инструмента: сначала попробуй решить задачу через SED, и только если он не справляется — переходи к AWK.
Синтаксис¶
Способы передачи данных¶
# Через конвейер — самый распространённый способ
echo "Text fragment" | sed 's/fragment/example/'
# → Text example
# Через heredoc — удобно для многострочного ввода
sed 's/old/new/' <<EOF
old line 1
old line 2
old line 3
EOF
# → new line 1
# → new line 2
# → new line 3
# Через herestring — для одной строки
sed 's/Hello/Привет/' <<< "Hello World"
# → Привет World
# Через файл — два эквивалентных варианта
sed 's/old/new/' < file.txt # через перенаправление
sed 's/old/new/' file.txt # файл как аргумент
# Process Substitution (Bash) — вывод команды как файл
sed 's/root/ROOT/' < <(grep "root" /etc/passwd)
# Обработка нескольких файлов — по умолчанию конкатенируются
sed 's/old/new/' file1.txt file2.txt file3.txt
# Обработать каждый файл ОТДЕЛЬНО (не конкатенировать)
# Полезно когда нужно считать строки в каждом файле независимо
sed -s 's/old/new/' file1.txt file2.txt
# НЕЛЬЗЯ: конвейер игнорируется при herestring
echo "text" | sed 'p' <<< "other" # ❌ данные из echo проигнорируются
Как SED обрабатывает строки¶
SED обрабатывает каждую строку в три шага:
┌─────────────────────────────────────────────────────┐
│ 1. Прочитать строку → поместить в pattern space │
│ 2. Применить все команды микропрограммы │
│ 3. Вывести pattern space в STDOUT (авто-печать) │
└─────────────────────────────────────────────────────┘
⚠️ Важно про автоматическую печать: SED всегда выводит содержимое
pattern spaceв конце каждого цикла — если не указана опция-n. Командаpдобавляет дополнительный вывод, что приводит к дублированию.
# Проблема дублирования
sed 'p' <<< "Hello World"
# Hello World ← вывод команды p
# Hello World ← автоматическая печать в конце цикла
# Решение: подавить автоматическую печать опцией -n
sed -n 'p' <<< "Hello World"
# Hello World ← только вывод команды p
# Практический пример: вывести только строки с "error"
# БЕЗ -n — каждая строка выведется, строки с "error" — дважды
sed '/error/p' log.txt # ❌ дублирование
# С -n — выведутся только строки с "error"
sed -n '/error/p' log.txt # ✅ правильно
# Команда замены s — работает с автоматической печатью
# (сама по себе НЕ печатает, только изменяет pattern space)
echo "Today is DATE" | sed 's/DATE/Monday/'
# → Today is Monday ← одна строка, всё правильно
# Но с модификатором p нужна опция -n
echo "Today is DATE" | sed -n 's/DATE/Monday/p'
# → Today is Monday ← напечатает только если замена была
Флаги и опции¶
| Флаг | Описание |
|---|---|
-n / --silent |
Подавить автоматическую печать |
-e 'команда' |
Передать команду напрямую (можно несколько) |
-f файл |
Читать микропрограмму из файла |
-i[суффикс] |
Редактировать файл на месте (in-place) |
-i.bak |
Редактировать на месте с созданием резервной копии .bak |
-E / -r |
Использовать ERE (расширенные регулярные выражения) |
-s / --separate |
Обрабатывать каждый файл отдельно |
-b / --binary |
Бинарный режим (для файлов с CRLF окончаниями строк) |
# -n — подавить автоматическую печать
# Без -n: выводятся все строки, строка с "error" — дважды
sed '/error/p' log.txt
# С -n: выводятся только строки с "error"
sed -n '/error/p' log.txt
# -e — несколько команд в одной строке
# Каждая -e добавляет команду в микропрограмму
sed -e 's/foo/bar/' -e 's/baz/qux/' -e '/^$/d' file.txt
# Эквивалентно:
sed 's/foo/bar/;s/baz/qux/;/^$/d' file.txt
# -f — микропрограмма из файла
# Удобно для сложных скриптов или повторного использования
cat > myrules.sed << 'EOF'
s/foo/bar/g
s/baz/qux/g
/^$/d
EOF
sed -f myrules.sed file.txt
# -i — редактирование файла на месте
# ВНИМАНИЕ: оригинал будет перезаписан без возможности восстановления!
echo "old value" > test.txt
sed -i 's/old/new/' test.txt
cat test.txt # → new value
# -i.bak — с созданием резервной копии
sed -i.bak 's/old/new/' test.txt
# Создаёт: test.txt (изменённый) и test.txt.bak (оригинал)
ls test.txt* # test.txt test.txt.bak
# -E — расширенные регулярные выражения (ERE)
# В ERE не нужно экранировать скобки и квантификаторы
sed -E 's/(foo|bar)/baz/g' file.txt # ERE: скобки без экранирования
sed 's/\(foo\|bar\)/baz/g' file.txt # BRE: то же самое, но с экранированием
# -s — обработка файлов по отдельности
# Без -s: $ означает конец последнего файла
sed -n '$p' file1.txt file2.txt # выведет последнюю строку file2.txt
# С -s: $ означает конец каждого файла отдельно
sed -sn '$p' file1.txt file2.txt # выведет последнюю строку каждого файла
# -b — бинарный режим для Windows-файлов (CRLF → LF)
sed -b 's/\r//' windows_file.txt # удалить символы \r
Структура микропрограммы¶
# Одна команда без адреса — применяется ко ВСЕМ строкам
sed 's/a/A/' file.txt
# Команда с адресом — применяется только к строке 2
sed '2s/a/A/' file.txt
# Команда с диапазоном — строки со 2 по 5
sed '2,5s/a/A/' file.txt
# Блок команд для одного адреса
# Всё что в {} выполняется только для строки 1
sed '1 {
s/a/A/
s/b/B/
s/c/C/
}' file.txt
# Вложенные блоки
sed '1,10 {
/pattern/ {
s/old/new/
s/foo/bar/
}
}' file.txt
# ВАЖНО: адрес прикрепляется только к СЛЕДУЮЩЕЙ команде/блоку
# Здесь '1' относится только к первому p, второй p — для всех строк
sed -n '1 p ; p' file.txt
# Строка 1 напечатается дважды (p + p), остальные — один раз (второй p)
# Правильно — если нужно применить несколько команд к одному адресу:
sed -n '1 { p ; p }' file.txt # первая строка напечатается дважды
# Точка с запятой разделяет команды в однострочной записи
sed -n 'p;p;p' <<< "test" # напечатает "test" трижды
# Перевод строки — разделитель в многострочной записи
sed -n '
p
p
p
' <<< "test"
# Комментарии в многострочных микропрограммах
sed -n '
# Напечатать строки с "error"
/error/ p
# Напечатать строки с "warning"
/warning/ p
' log.txt
Адресация строк¶
Числовая адресация¶
# Файл text.txt:
# строка 1
# строка 2
# строка 3
# строка 4
# строка 5
# Конкретная строка — напечатать вторую строку
sed -n '2p' text.txt
# строка 2
# Диапазон строк (с 2 по 4 включительно)
sed -n '2,4p' text.txt
# строка 2
# строка 3
# строка 4
# Специальный символ $ — последняя строка
sed -n '$p' text.txt
# строка 5
# С третьей строки до конца файла
sed -n '3,$p' text.txt
# строка 3
# строка 4
# строка 5
# Только первая строка — часто используется для заголовков
sed -n '1p' text.txt
# строка 1
# Все строки КРОМЕ первой (пропустить заголовок)
sed '1d' text.txt
# строка 2
# строка 3
# строка 4
# строка 5
# Заменить только во второй строке
sed '2s/строка/line/' text.txt
# строка 1
# line 2
# строка 3
# строка 4
# строка 5
# Удалить строки с 2 по 4
sed '2,4d' text.txt
# строка 1
# строка 5
Адресация по регулярному выражению¶
# Файл с маркерами:
# строка 1
# start
# строка 3
# строка 4
# end
# строка 6
# Строки, содержащие "start"
sed -n '/start/p' text.txt
# start
# Диапазон от "start" до "end" включительно
# AWK начнёт вывод со строки "start" и закончит на "end"
sed -n '/start/,/end/p' text.txt
# start
# строка 3
# строка 4
# end
# Комбинирование: от "start" до последней строки
sed -n '/start/,$p' text.txt
# start
# строка 3
# строка 4
# end
# строка 6
# Комбинирование: с первой строки до "end"
sed -n '1,/end/p' text.txt
# строка 1
# start
# строка 3
# строка 4
# end
# По регулярному выражению — строки с цифрами
sed -n '/[0-9]/p' text.txt
# Замена только в строках с "pattern"
sed '/pattern/s/old/new/' file.txt
# Объяснение: сначала выбираем строки с "pattern", потом в них делаем замену
# Удаление строк по шаблону
sed '/^#/d' config.txt # удалить комментарии (строки начинающиеся с #)
sed '/^$/d' file.txt # удалить пустые строки
sed '/ERROR/d' log.txt # удалить строки с "ERROR"
Продвинутая адресация (только GNU SED)¶
# строка~шаг — каждую N-ю строку начиная с M-й
# Синтаксис: первая~шаг
# Нечётные строки (начиная с 1-й, каждая вторая)
seq 8 | sed -n '1~2p'
# 1 3 5 7
# Чётные строки (начиная со 2-й, каждая вторая)
seq 8 | sed -n '2~2p'
# 2 4 6 8
# Каждая третья строка, начиная с 3-й
seq 9 | sed -n '3~3p'
# 3 6 9
# Практический пример: удалить каждую вторую строку
seq 6 | sed '2~2d'
# 1 3 5
# адрес,+N — адресованная строка и ещё N строк после неё
# Вывести строку 3 и ещё 2 после неё (строки 3, 4, 5)
seq 8 | sed -n '3,+2p'
# 3 4 5
# С regex: строка с "start" и ещё 3 строки после неё
sed -n '/start/,+3p' file.txt
# адрес,~N — от адресованной строки до ближайшей, кратной N
# С первой строки до ближайшей, кратной 5 (т.е. до строки 5)
seq 8 | sed -n '1,~5p'
# 1 2 3 4 5
# С третьей строки до ближайшей, кратной 4 (т.е. до строки 4)
seq 8 | sed -n '3,~4p'
# 3 4
Инверсия адресации — оператор !¶
# ! инвертирует адрес — команда выполняется для всех строк КРОМЕ указанных
# Всё КРОМЕ второй строки
sed -n '2 !p' file.txt
# Всё КРОМЕ строк со 2 по 4
sed -n '2,4 !p' file.txt
# Объяснение: строки 1, 5, 6, ... выводятся; строки 2, 3, 4 — нет
# Всё КРОМЕ строк с "pattern"
sed -n '/pattern/ !p' file.txt
# Эквивалентно: sed -n '/pattern/!p' file.txt (пробел необязателен)
# Удалить всё КРОМЕ строк с "keep"
sed '/keep/ !d' file.txt
# Обработать все файлы кроме первого — трюк с FNR/NR
# (в SED нет FNR, но есть -s для раздельной обработки)
# Инверсия с блоком — выполнить блок для всего кроме строк 2-4
sed -n '2,4 !{
s/a/A/
p
}' file.txt
# Практический пример: напечатать всё кроме комментариев и пустых строк
sed -n '/^#/ !{ /^$/ !p }' config.txt
# Или короче:
sed '/^#/d;/^$/d' config.txt
Разделители¶
По умолчанию разделитель команды s и y — слеш /. Если в шаблоне много слешей, можно использовать любой другой символ.
# Проблема: замена пути — много экранирования, плохо читается
sed 's/\/usr\/local\/bin\/old/\/usr\/local\/bin\/new/' file.txt
# Решение: сменить разделитель на |
sed 's|/usr/local/bin/old|/usr/local/bin/new|' file.txt
# Разделитель # — популярен для путей
sed 's#/usr/local/bin/old#/usr/local/bin/new#' file.txt
# Разделитель _ — если нет подчёркиваний в шаблоне
sed 's_/usr/local/bin/old_/usr/local/bin/new_' file.txt
# Разделитель @ — редко встречается в текстах
sed 's@/usr/local/bin@/opt/bin@g' file.txt
# Разделитель : — для команды y (трансформация символов)
# Перевести в нижний регистр
sed 'y:ABCDEFGHIJKLMNOPQRSTUVWXYZ:abcdefghijklmnopqrstuvwxyz:' <<< "RED ZONE"
# → red zone
# Разделитель в адресации по regex
# ВАЖНО: первый символ разделителя в адресации экранируется \
sed -n '\|/usr/local|p' /etc/paths # разделитель |
sed -n '\#/usr/local#p' /etc/paths # разделитель #
# В диапазоне — для каждой границы можно свой разделитель
sed -n '\|start|,\#stop#p' file.txt
# Когда разделитель встречается в шаблоне — экранировать
# Если шаблон содержит | и разделитель тоже |
sed 's|foo\|bar|baz|g' file.txt # экранируем | в шаблоне
# Практический пример: обновить URL в конфиге
sed 's|http://old-server.com|https://new-server.com|g' config.txt
# Практический пример: замена путей в скрипте
sed 's|/home/user/project|/opt/myapp|g' deploy.sh
Команда s — замена (подробно)¶
Самая используемая команда SED.
где <d> — разделитель (обычно /).
Модификаторы команды s¶
| Модификатор | Описание |
|---|---|
g |
Заменить все вхождения (по умолчанию только первое) |
N (число) |
Заменить только N-е вхождение |
i / I |
Игнорировать регистр |
p |
Напечатать результат (используется с -n) |
w файл |
Записать результат в файл |
# ==========================================
# Базовая замена — первое вхождение
# ==========================================
echo "This is an old text. Replace the old text." > sample.txt
# Заменить только ПЕРВОЕ вхождение "old" на "new"
sed 's/old/new/' sample.txt
# → This is an new text. Replace the old text.
# Обратите внимание: второе "old" НЕ заменилось!
# ==========================================
# Флаг g — заменить ВСЕ вхождения
# ==========================================
# Заменить ВСЕ вхождения "old" на "new"
sed 's/old/new/g' sample.txt
# → This is an new text. Replace the new text.
# Удалить все пробелы в строке
sed 's/ //g' <<< "hello world foo bar"
# → helloworldfoobar
# Удалить все цифры
sed 's/[0-9]//g' <<< "abc123def456"
# → abcdef
# ==========================================
# Числовой модификатор — N-е вхождение
# ==========================================
echo "one two three one two three" > nums.txt
# Заменить только ВТОРОЕ вхождение "one"
sed 's/one/ONE/2' nums.txt
# → one two three ONE two three
# Первое "one" не тронуто, второе заменено
# Заменить только ТРЕТЬЕ вхождение
echo "a a a a a" | sed 's/a/X/3'
# → a a X a a
# Заменить начиная со второго вхождения (комбинация 2 и g)
echo "a a a a a" | sed 's/a/X/2g'
# → a X X X X
# ==========================================
# Флаг i — игнорировать регистр
# ==========================================
# Заменить "error" независимо от регистра
echo "Error ERROR error ErRoR" | sed 's/error/ОШИБКА/gi'
# → ОШИБКА ОШИБКА ОШИБКА ОШИБКА
# Найти строки с "warning" в любом регистре и заменить
sed 's/WARNING/⚠️ WARNING/i' log.txt
# ==========================================
# Флаг p — напечатать только изменённые строки
# ==========================================
# Без -n — напечатает все строки, изменённые — дважды
sed 's/old/new/p' file.txt # ❌ дублирование
# С -n — напечатает только строки где произошла замена
sed -n 's/old/new/p' file.txt # ✅ только изменённые
# Практический пример: показать только изменённые строки конфига
sed -n 's/^#\(PasswordAuthentication\)/\1/p' /etc/ssh/sshd_config
# ==========================================
# Флаг w — записать результат в файл
# ==========================================
# Сохранить строки с заменой в отдельный файл
sed 's/ERROR/ОШИБКА/w errors_ru.log' app.log
# В errors_ru.log попадут только строки где была замена
# ==========================================
# Символы в строке замены
# ==========================================
# & — подставляет ВСЁ найденное совпадение целиком
echo "Price: 100" | sed 's/[0-9]*/[&]/'
# → Price: [100]
# [0-9]* нашло "100", & подставило "100", обернули в []
# Обернуть любое слово в кавычки
echo "hello world" | sed 's/[[:alpha:]]*/"&"/g'
# → "hello" "world"
# Добавить http:// перед доменом
echo "example.com" | sed 's/.*/http:\/\/&/'
# → http://example.com
# Лучше со сменой разделителя:
echo "example.com" | sed 's|.*|http://&|'
# → http://example.com
# \1, \2, ... — ссылки на группы захвата
# Группы в BRE: \(...\), в ERE: (...)
# Вывести только первое слово строки (BRE)
echo "Hello World Foo" | sed 's/\([[:alnum:]]*\).*/\1/'
# → Hello
# \([[:alnum:]]*\) — группа 1: захватывает слово
# .* — остаток строки (не в группе)
# \1 — подставляем группу 1
# Поменять местами имя и фамилию (ERE)
echo "Иванов Иван" | sed -E 's/([^ ]+) ([^ ]+)/\2 \1/'
# → Иван Иванов
# ([^ ]+) — группа 1: всё до пробела (фамилия)
# ([^ ]+) — группа 2: всё после пробела (имя)
# \2 \1 — имя + пробел + фамилия
# Добавить скобки вокруг кода города в телефоне
echo "Phone: 495-123-45-67" | sed -E 's/([0-9]{3})-([0-9]{3})/(\1)-\2/'
# → Phone: (495)-123-45-67
# Форматировать дату из YYYYMMDD в YYYY-MM-DD
echo "20231225" | sed -E 's/([0-9]{4})([0-9]{2})([0-9]{2})/\1-\2-\3/'
# → 2023-12-25
# ==========================================
# Замена на конкретной строке
# ==========================================
# Заменить только в первой строке
sed '1s/old/new/' file.txt
# Заменить только в последней строке
sed '$s/old/new/' file.txt
# Заменить в строках с 2 по 5
sed '2,5s/old/new/g' file.txt
# Заменить только в строках с "pattern"
sed '/pattern/s/old/new/' file.txt
# Заменить во всех строках КРОМЕ первой
sed '1 !s/old/new/' file.txt
# Практический пример: изменить значение параметра в конфиге
sed 's/^timeout=.*/timeout=30/' config.ini
# ^ — начало строки, чтобы не зацепить inline комментарии
# .* — всё что идёт после =
# ==========================================
# Практические примеры замены
# ==========================================
# Убрать ведущие пробелы (ltrim)
echo " hello world" | sed 's/^[[:space:]]*//'
# → hello world
# ^ — начало строки
# [[:space:]]* — ноль или более пробельных символов
# Убрать хвостовые пробелы (rtrim)
echo "hello world " | sed 's/[[:space:]]*$//'
# → hello world
# [[:space:]]* — ноль или более пробельных символов
# $ — конец строки
# Убрать ВСЕ пробелы по краям (trim) — два вызова s
echo " hello world " | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
# → hello world
# Удалить комментарии (от # до конца строки)
echo "param=value # это комментарий" | sed 's/#.*//'
# → param=value
# Удалить комментарии И хвостовые пробелы после них
echo "param=value # комментарий" | sed 's/[[:space:]]*#.*//'
# → param=value
# Заменить множественные пробелы одним
echo "hello world foo" | sed 's/[[:space:]][[:space:]]*/ /g'
# → hello world foo
# [[:space:]] — один пробельный символ
# [[:space:]]* — ноль или более дополнительных
# Вместе: один или более пробелов → один пробел
# Удалить ANSI escape-коды (цвета в терминале)
sed 's/\x1b\[[0-9;]*m//g' colored_output.txt
# Удалить Windows CRLF окончания строк (\r\n → \n)
sed 's/\r//' windows_file.txt
# или для редактирования на месте:
sed -i 's/\r$//' windows_file.txt
# Обновить версию в package.json
sed -i 's/"version": "[^"]*"/"version": "2.1.0"/' package.json
# "[^"]*" — любые символы кроме кавычки (содержимое строки)
# Экранировать специальные символы HTML
echo "<b>Hello & World</b>" | sed '
s/&/\&/g
s/</\</g
s/>/\>/g
'
# → <b>Hello & World</b>
# ВАЖНО: & нужно заменять первым, иначе & из \& тоже заменится
# Добавить текущую дату вместо токена DATE
sed "s/DATE/$(date +%Y-%m-%d)/" template.txt
# Двойные кавычки нужны для работы подстановки $()
Команда y — посимвольная трансформация¶
Аналог утилиты tr. Заменяет каждый символ из первой серии соответствующим символом из второй.
# Синтаксис: y/исходная_серия/целевая_серия/
# Длина обеих серий должна быть ОДИНАКОВОЙ!
# Перевести все буквы в нижний регистр
sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' <<< "HELLO WORLD"
# → hello world
# Перевести в верхний регистр
sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' <<< "hello world"
# → HELLO WORLD
# Заменить цифры символами (шифрование)
echo "12345" | sed 'y/0123456789/abcdefghij/'
# → bcdef
# 1→b, 2→c, 3→d, 4→e, 5→f
# Заменить точки запятыми (например, для числового формата)
echo "3.14159" | sed 'y/./,/'
# → 3,14159
# ROT13 — простое шифрование (буква смещается на 13 позиций)
echo "Hello World" | sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm/'
# → Uryyb Jbeyq
# Заменить пробелы подчёркиваниями (для имён файлов)
echo "my file name.txt" | sed 'y/ /_/'
# → my_file_name.txt
# С другим разделителем (удобно если в серии есть /)
echo "/usr/local/bin" | sed 'y|/|_|'
# → _usr_local_bin
# Разделитель : — удобен для кириллицы и спецсимволов
sed 'y:+-*/:abcd:' <<< "1+2-3*4/5"
# → 1a2b3c4d5
# Отличие от s — y применяется к КАЖДОМУ символу отдельно
# s/abc/xyz/ — заменяет подстроку "abc" целиком
# y/abc/xyz/ — заменяет a→x, b→y, c→z по всей строке
echo "abcabc" | sed 's/abc/xyz/' # → xyzabc (только первое вхождение)
echo "abcabc" | sed 'y/abc/xyz/' # → xyzxyz (каждый символ по всей строке)
Вставка, добавление, удаление строк (подробно)¶
Команда a — добавить строку ПОСЛЕ¶
# Добавить строку после КАЖДОЙ строки
sed 'a ---' file.txt
# Вывод:
# строка 1
# ---
# строка 2
# ---
# Добавить после второй строки
sed '2a Это добавленная строка' file.txt
# строка 1
# строка 2
# Это добавленная строка
# строка 3
# Добавить после последней строки (в конец файла)
sed '$a # Конец файла' config.txt
# Добавить после строки с "pattern"
sed '/\[database\]/a host=localhost' config.ini
# Найдёт строку [database] и добавит host=localhost после неё
# Добавить несколько строк (\ в конце каждой)
sed '/\[database\]/a\
host=localhost\
port=5432\
name=mydb' config.ini
# Практический пример: добавить заголовок лицензии в файлы
find . -name "*.py" | xargs sed -i '1a # Licensed under MIT License'
# Добавить пустую строку после каждого абзаца (строки с .)
sed '/\.$/ a\\' text.txt
Команда i — вставить строку ПЕРЕД¶
# Вставить перед второй строкой
sed '2i Это вставленная строка' file.txt
# строка 1
# Это вставленная строка
# строка 2
# строка 3
# Вставить в начало файла (перед первой строкой)
sed '1i #!/bin/bash' script.sh
# Добавляет shebang в начало
# Вставить заголовок перед первой строкой
sed '1i # Автогенерированный файл — не редактировать вручную!' config.txt
# Вставить перед строкой с "pattern"
sed '/^server {/i # Конфигурация сервера' nginx.conf
# Практический пример: добавить DOCTYPE перед <html>
sed '/<html>/i <!DOCTYPE html>' template.html
# Вставить несколько строк
sed '/^server {/i\
# Конфигурация сервера\
# Создано автоматически' nginx.conf
Команда c — заменить строку целиком¶
# Заменить вторую строку целиком
sed '2c Это новое содержимое строки 2' file.txt
# строка 1
# Это новое содержимое строки 2
# строка 3
# Заменить строку с "old_param"
sed '/^old_param=/c new_param=new_value' config.txt
# ВАЖНО: при замене диапазона — весь диапазон заменяется ОДНОЙ строкой
sed '2,4c Эта строка заменяет строки 2, 3 и 4' file.txt
# строка 1
# Эта строка заменяет строки 2, 3 и 4
# строка 5
# Практический пример: заменить строку с устаревшим параметром
sed '/^PermitRootLogin yes/c PermitRootLogin no' /etc/ssh/sshd_config
# Заменить строку на несколько строк
sed '/pattern/c\
Первая строка замены\
Вторая строка замены' file.txt
Команда d — удалить строку¶
# Удалить вторую строку
sed '2d' file.txt
# Удалить с 3 по 5 строку
sed '3,5d' file.txt
# Удалить последнюю строку
sed '$d' file.txt
# Удалить строки с "pattern"
sed '/ERROR/d' log.txt
# Удалить пустые строки
sed '/^$/d' file.txt
# ^ — начало строки
# $ — конец строки
# Если между ними ничего нет — строка пустая
# Удалить строки состоящие ТОЛЬКО из пробелов/табов
sed '/^[[:space:]]*$/d' file.txt
# Удалить строки-комментарии (начинающиеся с #)
sed '/^[[:space:]]*#/d' config.txt
# [[:space:]]* — возможные пробелы в начале
# # — символ комментария
# Удалить комментарии И пустые строки одной командой
sed '/^[[:space:]]*#/d;/^[[:space:]]*$/d' config.txt
# Удалить строки короче 5 символов
sed '/.\{5\}/!d' file.txt
# .\{5\} — любые 5 символов
# !d — удалить строки где это НЕ нашлось (т.е. строки короче 5)
# Удалить повторяющиеся подряд идущие строки (аналог uniq)
sed '$!N;/^\(.*\)\n\1$/!P;D' file.txt
# Объяснение:
# $!N — если не последняя строка, добавить следующую
# /^\(.*\)\n\1$/!P — если текущая != следующей, напечатать текущую
# D — удалить из pattern space до \n, начать новый цикл
# Практический пример: удалить строки из диапазона
sed '/^BEGIN$/,/^END$/d' file.txt
# Удалит строки от BEGIN до END включительно
Команда p — вывод строк¶
# Базовый вывод — с -n чтобы не было дублирования
sed -n '5p' file.txt # строка 5
sed -n '5,10p' file.txt # строки 5-10
sed -n '/error/p' file.txt # строки с "error"
sed -n '$p' file.txt # последняя строка
# Вывести первые 5 строк (как head -5)
sed -n '1,5p' file.txt
# Или через удаление (быстрее для больших файлов):
sed '6,$d' file.txt
# Вывести последние 3 строки (как tail -3)
sed -n -e :a -e '$p;N;3,$D;ba' file.txt
# Объяснение сложной конструкции:
# :a — метка начала цикла
# $p — если последняя строка — напечатать pattern space
# N — добавить следующую строку к pattern space
# 3,$D — если в pattern space 3+ строк — удалить первую
# ba — перейти к метке :a
# Вывести диапазон по шаблонам
sed -n '/^START/,/^END/p' file.txt
# Вывести строку ДО строки с "pattern" (предыдущая строка)
sed -n '/pattern/{x;p;d};x' file.txt
# Объяснение:
# /pattern/{ — если строка содержит "pattern":
# x — обменять pattern space и hold space
# p — напечатать (теперь в pattern space предыдущая строка)
# d — удалить (не выводить текущую строку)
# }
# x — для остальных строк: сохранить в hold space
# Вывести строку ПОСЛЕ строки с "pattern"
sed -n '/pattern/{n;p}' file.txt
# n — перейти к следующей строке
# p — напечатать её
# Вывести строки с номерами (как cat -n)
sed -n '=' file.txt | sed 'N;s/\n/\t/'
# = выводит номер строки, затем мы объединяем с самой строкой
Команда = — номера строк¶
# Вывести номера всех строк ПЕРЕД каждой строкой
sed '=' file.txt
# 1
# первая строка
# 2
# вторая строка
# Вывести только количество строк (номер последней = количество)
sed -n '$=' file.txt
# Это быстрее чем wc -l для простых случаев
# Вывести номер строки с "pattern"
sed -n '/pattern/=' file.txt
# Красивый вывод: номер строки + строка
sed '=' file.txt | sed 'N;s/\n/: /'
# 1: первая строка
# 2: вторая строка
# Вывести номера строк с форматированием (ведущие нули)
sed -n '=' file.txt | sed 's/^/ /;s/.*\(.\{5\}\)/\1/'
# 00001
# 00002
Команды r и w — чтение и запись файлов¶
# r — прочитать файл и вставить его содержимое
# Вставить содержимое файла ПОСЛЕ строки 3
sed '3r header.txt' main.txt
# Вставить файл после строки с "INSERT_HERE"
sed '/INSERT_HERE/r insert.txt' template.txt
# Вставить файл после последней строки (добавить в конец)
sed '$r footer.txt' main.txt
# Практический пример: шаблон с заменяемыми блоками
sed '/LICENSE_PLACEHOLDER/r license.txt' template.txt | \
sed '/LICENSE_PLACEHOLDER/d'
# Сначала вставляем файл после строки-плейсхолдера,
# потом удаляем саму строку-плейсхолдер
# w — записать строку в файл
# Записать строки с "error" в отдельный файл
sed -n '/error/w errors.log' app.log
# Записать строки 5-10 в файл
sed -n '5,10w output.txt' file.txt
# Разбить файл на части по шаблону
sed -n '/^[A-M]/w am.txt' names.txt # имена А-М
sed -n '/^[N-Z]/w nz.txt' names.txt # имена Н-Я
# Записать результат замены в файл
sed -n 's/ERROR/КРИТИЧЕСКАЯ ОШИБКА/pw critical.log' app.log
# p — напечатать, w — записать в файл
Работа с буферами (pattern space и hold space)¶
SED имеет два буфера: - pattern space — рабочий буфер, текущая обрабатываемая строка - hold space — вспомогательный буфер, пустой по умолчанию, сохраняется между строками
Команды работы с буферами:
h — скопировать pattern space → hold space (перезапись)
H — добавить pattern space к hold space (через \n)
g — скопировать hold space → pattern space (перезапись)
G — добавить hold space к pattern space (через \n)
x — поменять местами pattern space и hold space
# ==========================================
# G — добавить hold space к pattern space
# По умолчанию hold space пустой → добавляется пустая строка
# ==========================================
# Добавить пустую строку после каждой строки (двойной интервал)
sed 'G' file.txt
# Вывод:
# строка 1
# ← пустая строка из hold space
# строка 2
# ← пустая строка из hold space
# Убрать двойные пустые строки
sed 'n;/^$/d' file.txt
# n — перейти к следующей строке (пропустить чётные)
# /^$/d — удалить пустые строки
# ==========================================
# h и g — сохранить и восстановить строку
# ==========================================
# Дублировать первую строку в конце файла
sed -n '1h;1!p;${g;p}' file.txt
# 1h — сохранить первую строку в hold space
# 1!p — печатать все строки кроме первой
# ${ — в конце файла:
# g — загрузить hold space (первая строка)
# p — напечатать её
# }
# Вывести строку перед строкой с "MARKER"
sed -n '/MARKER/{x;p;d};x' file.txt
# Для строк без MARKER: x сохраняет текущую в hold space
# Для строки с MARKER: x загружает предыдущую строку, p печатает её
# ==========================================
# Вывод строк в обратном порядке (аналог tac)
# ==========================================
sed -n '1!G;h;$p' file.txt
# Объяснение:
# 1!G — для всех строк кроме первой: добавить hold space к pattern space
# (в hold space накапливаются предыдущие строки в обратном порядке)
# h — сохранить накопленное обратно в hold space
# $p — в конце файла напечатать всё накопленное
# Проследим для файла с 3 строками:
# Строка 1: 1!G не срабатывает; h сохраняет "1" в hold
# Строка 2: G добавляет "1" → pattern="2\n1"; h сохраняет "2\n1"
# Строка 3: G добавляет "2\n1" → pattern="3\n2\n1"; $p печатает "3\n2\n1"
# ==========================================
# Объединение подряд идущих строк попарно (GNU SED)
# ==========================================
printf "%s\n" a b c d e f | sed -n '1~2h; 2~2 { H; g; s/\n/ /; p }'
# → a b
# → c d
# → e f
# Объяснение:
# 1~2h — нечётные строки (1,3,5...): сохранить в hold space
# 2~2 { — чётные строки (2,4,6...):
# H — добавить к hold space (получаем "нечётная\nчётная")
# g — загрузить в pattern space
# s/\n/ / — заменить \n на пробел
# p — напечатать пару
# }
# ==========================================
# Захват абзацев (блоков разделённых пустыми строками)
# ==========================================
sed '/./{H;$!d} ; x ; s/^/\n>>> АБЗАЦ:\n/' text.txt
# Объяснение:
# /./ { — для непустых строк:
# H — добавить к hold space
# $!d — удалить из вывода (если не последняя строка)
# }
# x — когда встречаем пустую строку или EOF:
# обменять буферы (получаем накопленный абзац)
# s/^/.../ — добавить маркер начала абзаца
# ==========================================
# x — обмен буферами
# ==========================================
# Вывести только чётные строки в обратном порядке
sed -n 'h;n;x;p' file.txt
# h — сохранить нечётную строку в hold
# n — перейти к чётной строке
# x — обменять (в pattern space нечётная, в hold чётная)
# p — напечатать чётную
# Вставить строку-разделитель между каждыми двумя строками
sed 'x;/./p;x' file.txt
# Первый x: при первой строке hold space пуст → p не выводит ничего
# При второй строке: x загружает первую, p печатает разделитель если hold непустой
Команды n и N — работа с несколькими строками¶
# n — прочитать СЛЕДУЮЩУЮ строку в pattern space (ЗАМЕНЯЕТ текущую)
# N — ДОБАВИТЬ следующую строку к pattern space (через \n)
# ==========================================
# n — пропустить строку (перейти к следующей)
# ==========================================
# Удалить каждую вторую строку
sed 'n;d' file.txt
# n — перейти к следующей строке (чётная)
# d — удалить её
# Остаются нечётные строки
# Вывод чётных строк
sed -n 'n;p' file.txt
# n — перейти к следующей (чётной)
# p — напечатать её
# Добавить разделитель после каждой строки кроме последней
sed '$!{ n; i -------------------- }' file.txt
# ==========================================
# N — многострочная обработка
# ==========================================
# Соединить каждые ДВЕ строки в одну (через пробел)
sed 'N;s/\n/ /' file.txt
# N — добавить следующую строку (pattern space = "строка1\nстрока2")
# s/\n/ / — заменить \n на пробел → "строка1 строка2"
# Показать содержимое pattern space после N
printf "%s\n" aa bb cc dd | sed -n 'N;l'
# aa\nbb$ ← l показывает управляющие символы буквально
# cc\ndd$
# Объединить строки с обратным слешем (продолжение строки)
sed ':a;/\\$/N;s/\\\n//;ta' file.txt
# :a — метка
# /\\$/N — если строка заканчивается на \, добавить следующую
# s/\\\n// — удалить \ и \n
# ta — если замена была успешна — повторить
# Найти и заменить текст разбитый на ДВЕ строки
sed 'N;s/первая строка\nвторая строка/замена/' file.txt
# Объединить ВСЕ строки файла в одну (сначала всё загружаем)
sed ':a;N;$!ba;s/\n/ /g' file.txt
# :a — метка
# N — добавить следующую строку
# $!ba — если не конец файла — повторить (загрузить ещё одну)
# s/\n/ /g — заменить все \n на пробел
# Восстановить QP-кодирование (строки объединённые через =)
sed ':x ; /=$/ { N ; s/=\n//g ; bx }' encoded.txt
# :x — метка
# /=$/ { — если строка заканчивается на =:
# N — добавить следующую строку
# s/=\n//g — удалить = и \n (склеить)
# bx — повторить цикл (вдруг следующая тоже с =)
# }
# ==========================================
# D — удалить до первого \n и перезапустить цикл
# ==========================================
# Показать скользящее окно из 2 строк
printf "%s\n" 1 2 3 4 5 | sed -n 'N;P;D'
# 1
# 2
# 3
# 4
# Объяснение:
# N — добавить строку (pattern = "1\n2")
# P — напечатать до первого \n (→ "1")
# D — удалить до первого \n (pattern = "2"), перезапустить цикл
# Следующая итерация: N добавляет "3" (pattern = "2\n3"), P печатает "2"...
Переходы и метки¶
SED поддерживает goto-подобные переходы для построения циклов и ветвлений.
# ==========================================
# Объявление меток и безусловный переход b
# ==========================================
# :имя_метки — объявить метку
# b метка — безусловный переход на метку
# b — переход в КОНЕЦ цикла (пропустить оставшиеся команды)
# Ветвление: пропустить замену для строк с "SKIP"
sed '/SKIP/ b end ; s/a/A/g ; :end' file.txt
# Если строка содержит "SKIP" → перейти к :end (пропустить s/a/A/g)
# Иначе → выполнить замену, потом :end
# Пропустить несколько команд
sed '
/SKIP/ b end
s/foo/bar/g
s/baz/qux/g
s/old/new/g
:end
' file.txt
# Безусловный переход в конец цикла (b без метки)
sed '/^#/ b ; s/param/PARAM/' file.txt
# Для строк с # → перейти в конец (не применять замену)
# Для остальных → выполнить замену
# ==========================================
# Условный переход t (если s выполнилась успешно)
# ==========================================
# t метка — перейти на метку ЕСЛИ предыдущая команда s выполнила замену
# T метка — перейти на метку ЕСЛИ предыдущая s НЕ выполнила замену
# Повторять замену до тех пор пока есть вхождения
# (полезно для вложенных паттернов)
echo "aaa" | sed ':loop ; s/aa/a/ ; t loop'
# Первая итерация: s/aa/a/ → "aa" (успешно), t переходит к :loop
# Вторая итерация: s/aa/a/ → "a" (успешно), t переходит к :loop
# Третья итерация: s/aa/a/ → "a" (нет "aa", не выполнилась), t НЕ переходит
# Результат: a
# Удалить ведущие пробелы (более надёжный способ через цикл)
echo " hello" | sed ':loop ; s/^ / / ; t loop'
# Заменяет два пробела одним, повторяет пока есть замены
# ==========================================
# Практические примеры с переходами
# ==========================================
# if-else конструкция в SED
# "Если строка с 'error' — вывести с [ERR], иначе с [OK]"
sed '
/error/ b is_error
s/^/[OK] /
b end
:is_error
s/^/[ERR] /
:end
' log.txt
# Восстановить текст с переносом строки (QP)
sed ':x ; $!N ; s/=\n// ; tx ; P ; D' encoded.txt
# :x — метка
# $!N — добавить следующую строку (если не конец файла)
# s/=\n// — удалить = и \n
# tx — если замена была — перейти к :x (ещё раз проверить)
# P — напечатать до первого \n
# D — удалить до первого \n, перезапустить
# Удалить пустые строки в начале файла
sed '
:start
/^$/ {
N
b start
}' file.txt
# Пока строки пустые — добавляем следующую и возвращаемся
# Когда встречаем непустую строку — pattern space содержит все
# накопленные пустые строки + первую непустую, s/\n*// их удаляет
# Бесконечная петля (для демонстрации — НЕ запускать!)
echo "test" | sed ':loop ; b loop' # ❌ никогда не завершится
# n и N разрывают петлю когда данные кончаются
seq 5 | sed ':loop ; n ; b loop' # ✅ завершится на последней строке
Регулярные выражения в SED¶
По умолчанию SED использует BRE (Basic Regular Expressions). С флагом -E — ERE (Extended Regular Expressions).
Отличия BRE и ERE¶
| Конструкция | BRE | ERE (-E) |
|---|---|---|
| Группа | \(abc\) |
(abc) |
| Альтернатива | a\|b |
a\|b |
+ (1 или более) |
\+ |
+ |
? (0 или 1) |
\? |
? |
{m,n} повторения |
\{m,n\} |
{m,n} |
| Ссылка на группу | \1, \2 |
\1, \2 |
Классы символов POSIX¶
| Класс | Описание |
|---|---|
[[:alpha:]] |
Буквы (a-z, A-Z) |
[[:digit:]] |
Цифры (0-9) |
[[:alnum:]] |
Буквы и цифры |
[[:space:]] |
Пробельные символы (пробел, таб, \n) |
[[:blank:]] |
Пробел и табуляция |
[[:upper:]] |
Заглавные буквы |
[[:lower:]] |
Строчные буквы |
[[:punct:]] |
Знаки пунктуации |
[[:print:]] |
Печатаемые символы |
[[:graph:]] |
Печатаемые символы кроме пробела |
# ==========================================
# BRE — базовые регулярные выражения (по умолчанию)
# ==========================================
# Группы требуют экранирования \( \)
sed 's/\([[:alnum:]]*\) \([[:alnum:]]*\)/\2 \1/' <<< "John Doe"
# → Doe John
# \([[:alnum:]]*\) — группа 1: слово
# \([[:alnum:]]*\) — группа 2: второе слово
# \2 \1 — меняем местами
# Квантификатор + требует экранирования \+
sed 's/[0-9]\+/NUM/' <<< "foo 123 bar"
# → foo NUM bar
# ==========================================
# ERE — расширенные регулярные выражения (-E)
# ==========================================
# Группы без экранирования
sed -E 's/([[:alnum:]]+) ([[:alnum:]]+)/\2 \1/' <<< "John Doe"
# → Doe John
# Альтернатива
sed -E 's/(cat|dog)/animal/g' <<< "I have a cat and a dog"
# → I have a animal and a animal
# Квантификатор + без экранирования
sed -E 's/[0-9]+/NUM/g' <<< "foo 123 bar 456"
# → foo NUM bar NUM
# Квантификатор ? — ноль или одно вхождение
sed -E 's/colou?r/colour/g' <<< "color and colour"
# → colour and colour
# u? — ноль или одна буква u
# Повторения {m,n}
# Найти строки с 5-значными числами
sed -nE '/[0-9]{5}/p' file.txt
# Извлечь email-адреса
sed -nE 's/.*([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}).*/\1/p' file.txt
# Форматировать дату YYYYMMDD → YYYY-MM-DD
echo "Дата: 20231225" | sed -E 's/([0-9]{4})([0-9]{2})([0-9]{2})/\1-\2-\3/'
# → Дата: 2023-12-25
# Извлечь IP-адрес
echo "Сервер 192.168.1.100 недоступен" | \
sed -nE 's/.*([0-9]{1,3}(\.[0-9]{1,3}){3}).*/\1/p'
# → 192.168.1.100
# ==========================================
# Практические примеры регулярных выражений
# ==========================================
# Удалить HTML-теги
echo "<b>Жирный</b> и <i>курсив</i>" | sed 's/<[^>]*>//g'
# → Жирный и курсив
# [^>]* — любые символы кроме >
# Найти строки с IP-адресом
sed -nE '/^[0-9]{1,3}(\.[0-9]{1,3}){3}/p' file.txt
# Удалить строки с только пробелами и табуляцией
sed '/^[[:blank:]]*$/d' file.txt
# Найти строки с URL
sed -nE '/https?:\/\/[^ ]+/p' file.txt
# Извлечь только числа из строки
echo "abc 123 def 456 ghi" | sed -E 's/[^0-9 ]//g;s/ */ /g'
# → 123 456
# Добавить ведущий ноль к числам меньше 10
echo "Дата: 1-9-2023" | sed -E 's/\b([0-9])\b/0\1/g'
# → Дата: 01-09-2023
# \b — граница слова (работает в GNU SED)
Регистр символов (только GNU SED)¶
# \u — следующий символ в ВЕРХНИЙ регистр
# \U — все последующие символы в ВЕРХНИЙ регистр
# \l — следующий символ в нижний регистр
# \L — все последующие символы в нижний регистр
# \E — конец преобразования регистра
# Перевести всю строку в верхний регистр
sed 's/.*/\U&/' <<< "hello world"
# → HELLO WORLD
# & — всё найденное совпадение (вся строка), \U — в верхний регистр
# Перевести в нижний регистр
sed 's/.*/\L&/' <<< "HELLO WORLD"
# → hello world
# Каждое слово с заглавной буквы (Title Case)
sed 's/\b./\u&/g' <<< "hello world foo bar"
# → Hello World Foo Bar
# \b. — первый символ каждого слова
# \u — в верхний регистр
# Первая буква заглавная, остальные строчные (Sentence case)
sed 's/.*/\u\L&/' <<< "hELLO wORLD"
# → Hello world
# \u\L — первый символ заглавный, далее все строчные
# Заглавная только первая буква каждого слова + остальные строчные
sed -E 's/([[:alpha:]])([[:alpha:]]*)/\u\1\L\2/g' <<< "hELLO wORLD"
# → Hello World
# Перевести в верхний регистр только первое слово
sed 's/[[:alpha:]]*/\U&/' <<< "hello world"
# → HELLO world
# [[:alpha:]]* — первое слово (до первого не-буквенного символа)
# Изменить регистр только в части строки
sed 's/\(ERROR\)/\L\1/' <<< "This is an ERROR message"
# → This is an error message
# Комбинация: имя в заглавном регистре, фамилия в нижнем
echo "ИВАН ИВАНОВ" | sed 's/\([^ ]*\) \([^ ]*\)/\u\L\1 \L\2/'
# → Иван иванов
Подстановки командной оболочки в микропрограмме¶
# Одинарные кавычки — Shell НЕ интерпретирует содержимое
sed 's/old/new/' file.txt # $ и другие спецсимволы не интерпретируются
# Двойные кавычки — Shell интерпретирует содержимое
# Позволяет использовать переменные и подстановки команд
version="2.0.0"
sed "s/VERSION/$version/" template.txt
# Подстановка команды прямо в sed
sed "s/DATE/$(date +%Y-%m-%d)/" template.txt
# Переменная с путём — нужно экранировать /
path="/usr/local/bin"
safe_path="${path//\//\\/}" # заменить / на \/
sed "s|OLD_PATH|$path|" file.txt # лучше — сменить разделитель на |
# Склейка одинарных и двойных кавычек для безопасной подстановки
pattern="[0-9]+"
sed -n '\''/'"$pattern"'/'\''p' file.txt
# Сложно читается — лучше использовать -e:
sed -n -e "/$pattern/p" file.txt
# Переменная как разделитель (нестандартный трюк)
SEP="|"
sed "s${SEP}old${SEP}new${SEP}g" file.txt
# Имитация grep с поддержкой переменной шаблона
search_pattern="error|warning"
sed -nE "/$search_pattern/p" log.txt
# Безопасная передача переменной (без риска инъекции)
# Если переменная содержит специальные символы SED
user_input="fo/o"
# ОПАСНО — если user_input содержит /:
sed "s/$user_input/bar/" file.txt # ❌ сломается
# БЕЗОПАСНО — через переменную SED:
sed -e "s|$user_input|bar|" file.txt # ✅ если | не в строке
# Сгенерировать sed-команды из другого файла и выполнить
# Пример: users.txt содержит "ID NAME", создаём замены ID→NAME
sed $(awk '{print "-e s/"$1"/"$2"/"}' users.txt) contacts.txt
Скрипты SED в файлах¶
# ==========================================
# Создание и запуск скрипта
# ==========================================
cat << 'EOF' > cleanup.sed
# Скрипт очистки конфигурационного файла
# Использование: sed -nf cleanup.sed config.txt
# Удалить inline комментарии (от # до конца строки)
s/#.*//
# Удалить хвостовые пробелы и табуляцию
s/[[:blank:]]*$//
# Удалить пустые строки
/^$/ d
# Напечатать оставшееся
p
EOF
# Запустить
sed -nf cleanup.sed /etc/ssh/sshd_config
# Запустить для нескольких файлов
sed -nf cleanup.sed /etc/nginx/nginx.conf /etc/ssh/sshd_config
# ==========================================
# Несколько скриптов
# ==========================================
# Скрипты выполняются последовательно (как -e)
sed -f normalize.sed -f format.sed -f cleanup.sed file.txt
# ==========================================
# SED как исполняемый скрипт (shebang)
# ==========================================
cat << 'EOF' > transform.sed
#!/bin/sed -f
# Трансформировать CSV: заменить разделитель , на ;
# и перевести заголовки в верхний регистр
1 s/.*/\U&/ # первая строка (заголовок) — в верхний регистр
s/,/;/g # заменить разделитель
EOF
chmod +x transform.sed
cat data.csv | ./transform.sed
# ==========================================
# Шаблонный препроцессор
# ==========================================
cat << 'EOF' > report.rules.sed
# Правила форматирования отчёта
# Заголовок нулевого уровня
/h\.0\..*/ {
i ================================================================================
a ================================================================================
s/h\.0\.\(.*\)/ \U\1/
}
# Заголовок первого уровня
/h\.1\..*/ {
i --------------------------------------------------------------------------------
a --------------------------------------------------------------------------------
s/h\.1\.\(.*\)/ \1/
}
# Вставить файл лицензии
/LICENSE/ {
r license.txt
d
}
# Напечатать результат
p
EOF
sed -nf report.rules.sed template.txt > report.txt
Практические примеры¶
Очистка конфигурационных файлов¶
# Показать конфиг без комментариев и пустых строк
sed -n '
s/#.*// # удалить комментарии
s/[[:blank:]]*$// # удалить хвостовые пробелы
/^$/ d # удалить пустые строки
p # напечатать оставшееся
' /etc/ssh/sshd_config
# Результат — только активные параметры:
# PasswordAuthentication no
# UsePAM yes
# X11Forwarding yes
# Одной строкой
sed -n 's/#.*//;s/[[:blank:]]*$//;/^$/ d;p' /etc/ssh/sshd_config
# Показать только строки с параметрами (ключ=значение)
sed -nE '/^[[:alpha:]_]+=/p' config.ini
Редактирование конфигурационных файлов¶
# Изменить значение параметра
sed -i 's/^timeout=.*/timeout=30/' config.ini
# ^ — начало строки (чтобы не зацепить другие параметры)
# .* — всё что идёт после = (старое значение)
# Раскомментировать параметр (убрать # в начале)
sed -i 's/^#\(PasswordAuthentication\)/\1/' /etc/ssh/sshd_config
# \(...\) — группа захвата
# \1 — подставить содержимое группы (без #)
# Закомментировать параметр
sed -i 's/^\(PermitRootLogin\)/#\1/' /etc/ssh/sshd_config
# Добавить параметр в секцию конфига
sed -i '/^\[database\]/a host=localhost\nport=5432' config.ini
# Заменить значение только если оно равно конкретному
sed -i '/^log_level=debug/c log_level=info' config.ini
# Обновить URL во всех конфигах рекурсивно
find /etc/myapp -name "*.conf" | \
xargs sed -i 's|http://old.server.com|https://new.server.com|g'
# Раскомментировать всю секцию (строки начинающиеся с #param)
sed -i '/^\[section\]/,/^\[/ s/^#//' config.ini
# От [section] до следующей секции: убрать # в начале строки
Форматирование текста¶
# Двойной интервал — добавить пустую строку после каждой
sed 'G' file.txt
# Убрать двойные пустые строки (оставить одинарные)
sed '/^$/{ N; /^\n$/d }' file.txt
# Если строка пустая и следующая тоже — удалить
# (оставит только первую из нескольких подряд пустых строк)
# Добавить отступ к элементам списка (строки начинающиеся с *)
sed 's/^\* / * /' list.txt
# Подчеркнуть заголовок (добавить строку из тире после)
sed '/^Заголовок/a ─────────────────────' text.txt
# Добавить рамку вокруг каждой строки
sed 's/.*/| & |/' file.txt
# Выровнять по левому краю (убрать ведущие пробелы)
sed 's/^[[:space:]]*//' file.txt
# Пронумеровать строки красиво
sed '=' file.txt | sed 'N;s/\n/\t/' | \
sed 's/^/ /;s/ *\(.\{4\}\)/\1/'
# Добавить блок BEFORE/AFTER вокруг каждого абзаца
sed 's/^/ /' paragraphs.txt # отступ для каждой строки
Работа с логами¶
# Извлечь строки с ошибками
sed -n '/\[ERROR\]/p' app.log
# Извлечь блок между метками START и END
sed -n '/\[START\]/,/\[END\]/p' app.log
# Удалить строки DEBUG (уменьшить объём лога)
sed '/\[DEBUG\]/d' app.log > filtered.log
# Заменить IP-адреса для безопасного шаринга логов
sed -E 's/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/X.X.X.X/g' access.log
# Добавить метку [CRITICAL] к строкам с кодом 500
sed '/HTTP\/[0-9.]* 500/ s/^/[CRITICAL] /' access.log
# Извлечь только HTTP-коды ответа из Nginx лога
sed -nE 's/.*" ([0-9]{3}) .*/\1/p' access.log | sort | uniq -c | sort -rn
# Показать последние 50 ошибок (tail + sed)
tail -1000 app.log | sed -n '/ERROR/p' | tail -50
# Раскрасить вывод (добавить ANSI-коды)
sed 's/ERROR/\x1b[31m&\x1b[0m/;s/WARNING/\x1b[33m&\x1b[0m/' log.txt
# \x1b[31m — красный цвет
# \x1b[33m — жёлтый цвет
# \x1b[0m — сброс цвета
Обработка CSV и таблиц¶
# Пример data.csv:
# name,age,city,salary
# Alice,30,Moscow,75000
# Bob,25,SPb,60000
# Удалить заголовок
sed '1d' data.csv
# Сохранить только заголовок
sed -n '1p' data.csv
# Добавить вычисляемый столбец (нет арифметики — добавим текст)
sed '1s/$/,department/;2,$s/$/,Engineering/' data.csv
# Заменить разделитель , на ;
sed 's/,/;/g' data.csv
# Удалить последний столбец
sed 's/,[^,]*$//' data.csv
# Вывести только строки с "Moscow"
sed -n '/,Moscow,/p' data.csv
# Заменить пустые поля на "N/A"
sed 's/,,/,N\/A,/g;s/,$/,N\/A/' data.csv
Сравнение файлов и формирование данных¶
# Заменить ID на имена используя внешний файл с маппингом
# users.txt: "1001 Alice Brown"
# contacts.txt: "1001 3L24 555-0124"
sed $(sed -n '3,$p' users.txt | \
awk '{print "-e s/"$1"/"$2"_"$3"/"}') \
contacts.txt | \
tr '_' ' '
# Объяснение:
# sed извлекает строки данных из users.txt
# awk создаёт команды вида: -e s/1001/Alice_Brown/
# внешний sed применяет эти замены к contacts.txt
# tr заменяет _ на пробел (чтобы имя с пробелом работало)
Редактирование нескольких файлов¶
# Замена в нескольких файлах — вывод в STDOUT
sed 's/old/new/g' file1.txt file2.txt file3.txt
# Замена прямо в файлах (in-place)
sed -i 's/old/new/g' file1.txt file2.txt
# С резервными копиями
sed -i.bak 's/old/new/g' file1.txt file2.txt
# Создаёт: file1.txt.bak, file2.txt.bak
# Создать разные суффиксы — через цикл
for f in *.conf; do
sed -i".${f}.bak" 's/old/new/g' "$f"
done
# Рекурсивное редактирование всех .txt файлов
find . -type f -name "*.txt" -exec sed -i 's/old/new/g' {} \;
# Через xargs — быстрее для большого числа файлов
find . -type f -name "*.txt" | xargs sed -i 's/old/new/g'
# С фильтром — только файлы содержащие "old"
grep -rl "old" . | xargs sed -i 's/old/new/g'
# Обработать каждый файл отдельно (не конкатенировать)
sed -s 's/old/new/g' file1.txt file2.txt
# Обработать файлы с Windows CRLF
sed -b 's/\r//' file.txt # бинарный режим
Полезные однострочники¶
# ==========================================
# Работа со строками
# ==========================================
# Удалить пустые строки
sed '/^$/d' file.txt
# Удалить строки состоящие только из пробелов
sed '/^[[:space:]]*$/d' file.txt
# Удалить комментарии и пустые строки
sed '/^[[:space:]]*#/d;/^[[:space:]]*$/d' file.txt
# Удалить повторяющиеся ПОДРЯД ИДУЩИЕ строки (аналог uniq)
sed '$!N;/^\(.*\)\n\1$/!P;D' file.txt
# Вывести строки в обратном порядке (аналог tac)
sed -n '1!G;h;$p' file.txt
# Добавить нумерацию строк (аналог cat -n)
sed '=' file.txt | sed 'N;s/\n/\t/'
# ==========================================
# Извлечение данных
# ==========================================
# Вывести строки с N по M
sed -n '5,10p' file.txt
# Вывести первые N строк (аналог head -5)
sed '6,$d' file.txt
# Вывести последние 3 строки (аналог tail -3)
sed -n -e :a -e '$p;N;3,$D;ba' file.txt
# Вывести строку ПЕРЕД строкой с "pattern"
sed -n '/pattern/{x;p;d};x' file.txt
# Вывести строку ПОСЛЕ строки с "pattern"
sed -n '/pattern/{n;p}' file.txt
# Вывести строки С контекстом (±2 строки вокруг "error")
sed -n '/error/{
# сохранить текущую
h
# взять 2 строки до
x
# напечатать контекст
p
}' file.txt
# ==========================================
# Форматирование
# ==========================================
# Двойной интервал (пустая строка после каждой)
sed 'G' file.txt
# Убрать двойной интервал
sed 'n;/^$/d' file.txt
# Добавить строку в начало файла
sed -i '1i # Добавленная первая строка' file.txt
# Добавить строку в конец файла
sed -i '$a # Добавленная последняя строка' file.txt
# Удалить HTML-теги
sed 's/<[^>]*>//g' file.html
# Удалить ANSI escape-коды (цвета)
sed 's/\x1b\[[0-9;]*m//g' colored.txt
# Заменить табы на 4 пробела
sed 's/\t/ /g' file.txt
# Удалить Windows CRLF
sed -i 's/\r$//' file.txt
# Объединить все строки в одну
sed ':a;N;$!ba;s/\n/ /g' file.txt
# Разбить строку по N символов (каждые 80 символов — новая строка)
sed 's/.\{80\}/&\n/g' long_line.txt
# ==========================================
# Подсчёт
# ==========================================
# Количество строк в файле
sed -n '$=' file.txt
# Количество непустых строк
sed '/^$/d' file.txt | sed -n '$='
# Количество строк с "pattern"
sed -n '/pattern/p' file.txt | sed -n '$='
Escape-последовательности¶
| Последовательность | Символ |
|---|---|
\n |
Новая строка |
\t |
Табуляция |
\r |
Возврат каретки |
\\ |
Обратный слеш |
\xNN |
Символ в шестнадцатеричной нотации (GNU SED) |
\u |
Следующий символ в верхний регистр (GNU SED) |
\U |
Все последующие в верхний регистр (GNU SED) |
\l |
Следующий символ в нижний регистр (GNU SED) |
\L |
Все последующие в нижний регистр (GNU SED) |
\E |
Конец преобразования регистра (GNU SED) |
# Вставить табуляцию в строку замены
sed 's/,/\t/g' data.csv # CSV → TSV
# Вставить новую строку в замену
sed 's/;/\n/g' file.txt # каждый ; на новую строку
# Hex-код символа
sed 's/\x09/ /g' file.txt # \x09 = TAB → 4 пробела
# Комбинация регистра
sed 's/\b\(.\)/\u\1/g' text.txt # каждое слово с заглавной
Сравнение BRE / ERE / GNU SED¶
| Возможность | BRE | ERE (-E) |
GNU SED |
|---|---|---|---|
| Группы | \(...\) |
(...) |
оба варианта |
Квантификатор + |
\+ |
+ |
оба |
Квантификатор ? |
\? |
? |
оба |
| Альтернатива | a\|b |
a\|b |
оба |
{m,n} |
\{m,n\} |
{m,n} |
оба |
\U, \L, \u, \l |
❌ | ❌ | ✅ |
addr~step |
❌ | ❌ | ✅ |
addr,+N |
❌ | ❌ | ✅ |
| Метки и переходы | ✅ | ✅ | ✅ расширено |
-i in-place |
зависит от реализации | зависит | ✅ |
-s отдельные файлы |
❌ | ❌ | ✅ |
💡 macOS: стандартный BSD sed отличается от GNU sed. Для GNU sed используй
gsed(установить черезbrew install gnu-sed). Основные отличия: в-iнужен обязательный суффикс (sed -i '' 's/a/b/'), нет\+,\?,addr~step.
Коды выхода¶
| Код | Значение |
|---|---|
0 |
Успешное выполнение |
1 |
Синтаксическая ошибка в микропрограмме |
2 |
Ошибка при работе с файлами |
# Проверить код выхода
sed 's/old/new/' file.txt
echo "Код выхода: $?" # → 0
# Использовать в условиях скрипта
if sed -n '/pattern/q0;$q1' file.txt 2>/dev/null; then
echo "Паттерн найден"
else
echo "Паттерн не найден"
fi
# Обработка ошибок
sed -i.bak 's/old/new/g' file.txt || {
echo "Ошибка! Восстанавливаем из бэкапа..."
mv file.txt.bak file.txt
}
Шпаргалка — быстрый справочник¶
# ЗАМЕНА
sed 's/old/new/' # первое вхождение
sed 's/old/new/g' # все вхождения
sed 's/old/new/2' # только второе вхождение
sed 's/old/new/2g' # начиная со второго
sed 's/old/new/gi' # все, без учёта регистра
sed '3s/old/new/' # только в строке 3
sed '/pat/s/old/new/' # в строках с "pat"
sed '1 !s/old/new/' # во всех строках кроме первой
sed -i 's/old/new/g' f # изменить файл на месте
sed -i.bak 's/old/new/' f # с резервной копией
# ВЫВОД
sed -n 'p' # явная печать (подавить авто)
sed -n '3p' # строка 3
sed -n '3,7p' # строки 3-7
sed -n '$p' # последняя строка
sed -n '/pat/p' # строки с "pat"
sed -n '/a/,/b/p' # от строки с "a" до "b"
sed -n '1~2p' # нечётные строки (GNU)
sed -n '3,+2p' # строка 3 и ещё 2 после (GNU)
# УДАЛЕНИЕ
sed '3d' # строка 3
sed '3,5d' # строки 3-5
sed '/pat/d' # строки с "pat"
sed '/^$/d' # пустые строки
sed '/^#/d' # строки-комментарии
sed '2,4 !d' # всё КРОМЕ строк 2-4
# ВСТАВКА И ДОБАВЛЕНИЕ
sed '3i строка' # вставить ПЕРЕД строкой 3
sed '3a строка' # добавить ПОСЛЕ строки 3
sed '1i строка' # добавить в начало файла
sed '$a строка' # добавить в конец файла
sed '/pat/i строка' # вставить перед "pat"
sed '/pat/a строка' # добавить после "pat"
sed '3c строка' # заменить строку 3 целиком
# АДРЕСАЦИЯ
sed -n '1~2p' # нечётные строки
sed -n '2~2p' # чётные строки
sed -n '5,+3p' # строка 5 и ещё 3
sed '2,4 !p' # всё КРОМЕ строк 2-4
sed -n '$=' # количество строк в файле
# ФАЙЛЫ
sed -f script.sed file # скрипт из файла
sed -e 'cmd1' -e 'cmd2' # несколько команд
sed -n '/pat/w out.txt' # записать в файл
sed '3r insert.txt' # вставить файл после строки 3
find . -name "*.txt" -exec sed -i 's/a/b/g' {} \;
# БУФЕРЫ
sed 'G' # добавить пустую строку после каждой
sed -n '1!G;h;$p' # строки в обратном порядке
sed 'N;s/\n/ /' # объединить пары строк
# РЕГУЛЯРНЫЕ ВЫРАЖЕНИЯ
sed -E 's/(foo|bar)/baz/g' # ERE: альтернатива
sed 's/\([[:alnum:]]*\).*/\1/' # BRE: первое слово строки
sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/' # дата
# РЕГИСТР (только GNU SED)
sed 's/.*/\U&/' # всё в верхний регистр
sed 's/.*/\L&/' # всё в нижний регистр
sed 's/\b./\u&/g' # каждое слово с заглавной
# ПЕРЕХОДЫ (GNU SED)
sed ':a ; s/aa/a/ ; t a' # цикл до тех пор пока работает s
sed '/pat/b end ; s/a/b/ ; :end' # пропустить для "pat"