grep, sed и awk: примеры обработки текста в терминале Linux
grep находит строки по шаблону (grep -rn error /var/log), sed изменяет текст в потоке или в файле (sed -i 's/old/new/g' file), а awk работает с колонками и считает (awk '{print $1}' access.log). Вместе в конвейере они заменяют скрипт: grep фильтрует строки, sed правит текст, awk вырезает поля и агрегирует.
grep, sed и awk — три классические утилиты Linux для обработки текста. grep находит строки по шаблону, sed заменяет и удаляет текст в потоке, не открывая редактор, а awk разбивает строку на колонки и умеет считать. Ниже — grep sed awk примеры, которые реально нужны при разборе логов, конфигов и вывода команд, плюс типичные ошибки.
Когда что использовать
Все три инструмента читают текст построчно и пишут результат в стандартный вывод, поэтому их легко соединять через |. Разница — в задаче, которую каждый решает лучше всего.
| Задача | Инструмент | Пример |
|---|---|---|
| Найти строки с текстом | grep | grep ERROR app.log |
| Заменить текст | sed | sed 's/http:/https:/g' file |
| Удалить или показать строки по номеру | sed | sed -n '10,20p' file |
| Достать колонку | awk | awk '{print $1}' access.log |
| Посчитать сумму, среднее, группировку | awk | awk '{s+=$10} END {print s}' |
Простое правило: если нужно только отфильтровать — берите grep, если изменить текст — sed, если в тексте есть колонки или нужна арифметика — awk.
grep: поиск строк по шаблону
Базовые примеры grep
# Строки со словом error в файле
grep error /var/log/syslog
# Без учёта регистра: Error, ERROR, error
grep -i error app.log
# С номерами строк
grep -n "Connection refused" app.log
# Рекурсивно по каталогу, с именами файлов
grep -rn "DB_HOST" /etc/myapp/
# Только имена файлов, где есть совпадение
grep -rl "TODO" src/
# Инвертировать: всё, КРОМЕ комментариев и пустых строк
grep -v -e '^#' -e '^$' /etc/ssh/sshd_config
# Посчитать число совпавших строк
grep -c " 500 " access.log
Флаг -w ищет слово целиком: grep -w log не найдёт login. Флаг -F отключает регулярные выражения и ищет строку буквально — удобно, когда в шаблоне есть точки, скобки или звёздочки.
Контекст вокруг найденной строки
Ошибка в логе редко понятна по одной строке — нужен стек или запрос, который к ней привёл. Для этого есть флаги контекста:
# 3 строки после совпадения (After)
grep -A 3 "Traceback" app.log
# 2 строки до (Before)
grep -B 2 "OOM" /var/log/kern.log
# по 5 строк с обеих сторон (Context)
grep -C 5 "segfault" /var/log/syslog
Группы совпадений grep разделяет строкой --, так что вывод легко читать глазами.
grep и регулярные выражения
По умолчанию grep понимает базовые регулярки (BRE). С флагом -E включаются расширенные (ERE), где +, ?, | и скобки работают без обратных слэшей.
| Конструкция | Значение | Пример |
|---|---|---|
^ | начало строки | grep '^root' /etc/passwd |
$ | конец строки | grep 'bash$' /etc/passwd |
. | любой символ | grep 'h.t' |
* | 0 и более повторений | grep 'ab*c' |
+ (ERE) | 1 и более | grep -E '[0-9]+' |
| (ERE) | или | grep -E 'error|warn' |
[...] | один символ из набора | grep '[Ee]rror' |
# Строки с ошибками или предупреждениями
grep -E "ERROR|WARN" app.log
# Только IP-адреса из лога, по одному на строку (-o — печатать лишь совпадение)
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log
grep -P: вытащить значение между известными кусками
В GNU grep есть флаг -P — регулярки в стиле Perl. С ним доступны \K («забыть всё, что совпало до этого места») и просмотр вперёд, что позволяет вытащить только значение:
$ echo 'user_id=4821 status=ok' | grep -oP 'user_id=\K[0-9]+'
4821
$ grep -oP '"version":\s*"\K[^"]+' package.json
2.4.1
Флаг -P есть не во всех сборках grep (например, в BSD grep на macOS его нет), поэтому в переносимых скриптах лучше использовать sed или awk.
grep -q в условиях скриптов
grep -q ничего не печатает и только возвращает код выхода: 0 — найдено, 1 — нет. Так проверку можно записать прямо в if:
if grep -q "^PermitRootLogin no" /etc/ssh/sshd_config; then
echo "root-вход отключён"
fi
Это короче, чем сохранять вывод в переменную и проверять её на пустоту, и grep останавливается на первом совпадении.
sed: замена и удаление текста
Замена: команда s
Основная команда sed — s/шаблон/замена/флаги. Без флага g заменяется только первое совпадение в каждой строке.
# Вывести текст с заменой (файл не меняется)
sed 's/foo/bar/' file.txt
# Заменить все вхождения в строке
sed 's/foo/bar/g' file.txt
# Без учёта регистра (GNU sed)
sed 's/error/ERROR/gI' app.log
# Другой разделитель, если в тексте есть слэши
sed 's|/var/www|/srv/www|g' nginx.conf
sed -i: замена прямо в файле
Флаг -i записывает результат обратно в файл. Чтобы не потерять исходник, задайте суффикс резервной копии:
# Создаст config.ini.bak и изменит config.ini
sed -i.bak 's/^debug=true/debug=false/' config.ini
# Замена во всех .conf в каталоге
find /etc/myapp -name "*.conf" -exec sed -i 's/old-host/new-host/g' {} +
Перед массовой правкой сначала запустите команду без -i и посмотрите на вывод. На macOS (BSD sed) у -i обязательный аргумент: sed -i '' 's/a/b/' file.
Работа со строками по номеру и по шаблону
# Показать строки 10–20 (-n отключает автопечать, p — печать)
sed -n '10,20p' file.txt
# Удалить строку 5
sed '5d' file.txt
# Удалить последнюю строку
sed '$d' file.txt
# Удалить пустые строки и комментарии
sed -e '/^$/d' -e '/^#/d' nginx.conf
# Заменить только в строках, где есть "listen"
sed '/listen/s/80/8080/' nginx.conf
# Вставить строку после совпадения (GNU sed)
sed '/^\[mysqld\]/a max_connections = 500' my.cnf
Обратные ссылки и &
Часть шаблона в скобках можно подставить в замену через \1, \2, а символ & означает весь найденный текст.
# Поменять местами имя и фамилию (ERE через -E)
$ echo "Иванов Пётр" | sed -E 's/(\S+) (\S+)/\2 \1/'
Пётр Иванов
# Обернуть все числа в квадратные скобки
$ echo "port 8080, timeout 30" | sed -E 's/[0-9]+/[&]/g'
port [8080], timeout [30]
# Дату 2026-10-14 превратить в 14.10.2026
$ echo 2026-10-14 | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/'
14.10.2026
awk: колонки, условия и подсчёты
Вывод нужного столбца
awk делит каждую строку на поля по пробелам и табуляциям: $1 — первое поле, $2 — второе, $NF — последнее, $0 — вся строка.
# IP-адреса из лога nginx (первая колонка)
awk '{print $1}' /var/log/nginx/access.log
# Имя пользователя и shell из /etc/passwd (разделитель — двоеточие)
awk -F: '{print $1, $7}' /etc/passwd
# Последняя колонка
df -h | awk '{print $NF}'
# Свой разделитель при выводе
awk -F: -v OFS=';' '{print $1, $3}' /etc/passwd
Условия: печатать только нужные строки
Перед блоком в фигурных скобках можно поставить условие — awk выполнит действие только для подходящих строк.
# Пользователи с UID от 1000 (обычные, не системные)
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
# Запросы с кодом ответа 500 и выше (9-е поле в формате combined)
awk '$9 >= 500' access.log
# Строки, где 6-я колонка совпадает с регуляркой
awk '$6 ~ /POST/' access.log
# Файлы больше 100 МБ из вывода ls -l
ls -l | awk '$5 > 100*1024*1024 {print $9}'
BEGIN, END и NR: awk как маленькая программа
Блок BEGIN выполняется до чтения первой строки, END — после последней. NR хранит номер текущей строки, а в блоке END — общее их число.
# Сумма размеров ответов (10-е поле) в мегабайтах
awk '{sum += $10} END {printf "%.1f MB\n", sum/1024/1024}' access.log
# Среднее время ответа из последней колонки
awk '{s += $NF} END {if (NR) print s/NR}' timings.log
# Пропустить заголовок CSV
awk -F, 'NR > 1 {print $2}' users.csv
# Подсчёт запросов по IP: ассоциативный массив
awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' access.log | sort -rn | head
Последний пример — классика разбора логов: массив count с ключом-IP заменяет связку sort | uniq -c и легко расширяется, например до суммы трафика по каждому адресу.
Конвейеры: grep, sed и awk вместе
Настоящая сила — в комбинации. Каждый инструмент делает свою часть, а | передаёт результат дальше.
Топ-10 IP с ошибками 5xx
grep ' 50[0-9] ' /var/log/nginx/access.log \
| awk '{print $1}' \
| sort | uniq -c | sort -rn | head -10
412 203.0.113.45
118 198.51.100.7
36 192.0.2.19
Здесь grep грубо отсекает строки, awk вырезает поле, а sort | uniq -c считает повторы. Это можно записать и одним awk: awk '$9 ~ /^5/ {c[$1]++} END {for (i in c) print c[i], i}' access.log | sort -rn | head — так точнее, потому что проверяется именно колонка кода ответа.
Какие URL открывают чаще всего
awk '{print $7}' access.log | sed 's/?.*//' | sort | uniq -c | sort -rn | head
sed здесь отрезает query-строку, чтобы /search?q=a и /search?q=b считались одной страницей.
Значения из конфига без комментариев
grep -v '^\s*#' /etc/myapp/app.env | grep '=' | awk -F= '{print $1}'
Ошибки за конкретный час
grep '14/Oct/2026:03:' access.log | awk '$9 >= 500 {print $4, $7, $9}'
Типичные ошибки
- Двойные кавычки вместо одинарных в awk. В
awk "{print $1}"shell подставит свою переменную$1до запуска awk. Программу awk и выражения sed пишите в одинарных кавычках. - Забыли
gв sed. Без него заменяется только первое совпадение в строке, остальные остаются. sed -iбез проверки. Неудачная регулярка молча испортит файл. Сначала прогоните без-iили используйте-i.bak.+и|не работают в grep. Это расширенный синтаксис: нуженgrep -E(илиsed -E).- Точка в шаблоне.
grep 192.168.1.1найдёт и192x168y1z1: точка — это «любой символ». Используйтеgrep -Fили экранируйте\.. - Пробелы в колонках. Если поле может содержать пробелы (CSV, путь), задайте разделитель явно:
awk -F,илиawk -F'\t'. - Бесполезный cat.
cat file | grep xработает, ноgrep x fileкороче и не порождает лишний процесс.
Чем заменить grep, sed и awk
Для JSON эти утилиты неудобны: структуру лучше разбирать jq (jq '.items[] | select(.status=="active") | .name'), а YAML — yq. Для быстрого рекурсивного поиска по большим проектам часто используют ripgrep (команда rg), который по умолчанию учитывает .gitignore. Если привычнее синтаксис Perl, perl -pe 's/a/b/g' и perl -lane 'print $F[0]' заменяют sed и awk одной строкой. Но grep, sed и awk есть практически на любом сервере без установки — поэтому их стоит знать в первую очередь.
Итог
grep ищет строки, sed их изменяет, awk работает с колонками и считает. Запомните базовый набор: grep -rniE и -A/-B/-C, sed 's/.../.../g' с -i.bak и -n 'Np', awk -F с $1, $NF, условиями и блоком END. Из этих кирпичей собирается почти любой разбор логов. Эти grep sed awk примеры, вместе с find, jq и curl, разобраны на практике в лекции курса по Linux об обработке текста в терминале.
Частые вопросы
Чем отличается grep от egrep?
egrep — устаревший псевдоним для grep -E (расширенные регулярные выражения). Современные версии GNU grep выводят предупреждение при вызове egrep, поэтому пишите grep -E.
Как найти текст во всех файлах каталога в Linux?
Используйте grep -rn "текст" /путь: -r ищет рекурсивно, -n показывает номер строки. Чтобы ограничить типы файлов, добавьте --include="*.php".
Как заменить текст во многих файлах сразу?
Объедините поиск и sed: grep -rl "old" . | xargs sed -i 's/old/new/g'. Перед этим полезно сделать коммит или резервную копию.
Как вывести в awk несколько колонок через табуляцию?
Задайте выходной разделитель: awk -v OFS='\t' '{print $1, $3}' file. Без OFS поля через запятую разделяются пробелом.
Как в sed удалить пробелы в конце строк?
Команда sed -i 's/[[:space:]]*$//' file удаляет хвостовые пробелы и табуляции во всех строках файла.
Эта тема подробно разобрана с практикой в курсе «Linux: с нуля до уверенного администрирования».
Перейти к курсу