Learning Platform
Глоссарий Troubleshooting
Урок 08.01 · 22 мин
Начальный
grepRegexPCREripgrepText processing

Что такое grep и почему он базовый

grep — это утилита для поиска строк, соответствующих регулярному выражению, в текстовом потоке. Имя — акроним команды редактора ed: globally search for a regular expression and print matching lines. То есть g/re/p — выведи каждую строку, в которой совпадает regex.

Для DE grep — это первый инструмент при работе с логами:

# Сколько раз сегодня падал DAG?
$ grep "Task failed" /var/log/airflow/scheduler.log | wc -l
47

# Какие именно DAG?
$ grep "Task failed" /var/log/airflow/scheduler.log | awk '{print $NF}' | sort -u
load_orders
sync_dims
process_events

grep есть на любой UNIX-системе с самого начала — UNIX V4 (1973). Это POSIX-стандарт, есть везде: Linux, macOS, BSD, WSL, в minimal Docker-образах.

Базовый синтаксис

grep [OPTIONS] PATTERN [FILE...]
  • Если файлы не указаны — читает stdin.
  • PATTERN по умолчанию — basic regular expression (BRE). Это старый regex-стандарт с экранированием спец-символов: \(, \+, \?, \|.
  • Возвращает exit code: 0 если что-то нашёл, 1 если нет, 2 если ошибка.
$ grep ERROR app.log
2026-05-13 12:34:56 ERROR: connection refused
2026-05-13 12:35:01 ERROR: timeout

$ echo "hello" | grep world
$ echo $?
1   # ничего не нашлось

Это exit code критичен в скриптах: можно делать if grep -q ERROR log; then alert; fi.

Основные флаги

Флаги grep, которые надо знать

80% реальных запросов обходятся этими флагами.

-icase-insensitiveERROR, error, Error — все совпадут. Полезно когда логи смешанные (часть от systemd UPPERCASE, часть от python lowercase).
-vinvert match — НЕ совпадающиеОчень полезно для исключения шума: grep -v DEBUG | grep ERROR. Двойной фильтр через pipe — основной паттерн.
-nпоказать номера строкУдобно когда хочешь потом открыть файл в редакторе и прыгнуть на строку: vim +N file.
-cпосчитать совпадения, не выводитьgrep -c ERROR log -> просто число. Эквивалентно grep ERROR log | wc -l, но быстрее (не строит выходные буферы).
-lвывести только имена файловgrep -l TODO *.py — найди все Python-файлы со словом TODO. Удобно с pipe: grep -l ... | xargs sed -i ....
-Lинвертирует -l (файлы БЕЗ совпадения)Найти конфиги без определённой настройки: grep -L 'set -euo pipefail' *.sh — какие скрипты НЕ имеют strict mode.
-r или -Rрекурсивно по директорииgrep -r TODO src/ — обходит дерево. -R следует по symlinks, -r — нет (это GNU specific, на BSD дефолт другой).
-wmatch только целое словоgrep -w error — совпадёт 'error here', не совпадёт 'unerror' или 'errors'. Граница — non-word characters.
-A N / -B N / -C Nконтекст: After / Before / Contextgrep -C 3 ERROR log — выведет совпадение и 3 строки до и 3 после. Незаменимо для stack-trace в логах.
-qquiet — только exit codeДля условий: if grep -q PATTERN file; then ...; fi. Не печатает ничего, не открывает stdout буфер.

Работа с regex

По умолчанию grep использует BRE (basic regex). Чтобы получить ERE (extended regex) с привычным синтаксисом:

$ grep -E 'pattern' file
# или
$ egrep 'pattern' file    # alias, deprecated в GNU grep 3.8+

Разница между BRE и ERE:

ВозможностьBRE (grep)ERE (grep -E)
. любой символ..
* 0+ повторов**
+ 1+ повторов\++
? 0 или 1\??
`` альтернатива|
(...) группа\(...\)(...)
{n,m} диапазон\{n,m\}{n,m}

То есть в BRE привычные мета-символы надо экранировать, что обычно неудобно. Рекомендация: всегда -E (или используй ripgrep, который использует ERE-like синтаксис по умолчанию).

# ERROR или WARN
$ grep -E '(ERROR|WARN)' app.log

# Даты в формате YYYY-MM-DD
$ grep -E '[0-9]{4}-[0-9]{2}-[0-9]{2}' app.log

# Email (упрощённо)
$ grep -E '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' contacts.txt

PCRE: -P

Если нужна полная Perl-совместимая regex (lookahead, lookbehind, named groups, \d, \w):

$ grep -P '\d{4}-\d{2}-\d{2}' app.log
$ grep -P '(?<=user=)\w+' auth.log     # lookbehind: вывести user, не включая 'user='
$ grep -P '^(?!#)' config.txt          # negative lookahead: строки, НЕ начинающиеся с #

PCRE мощнее, но на больших файлах медленнее ERE. На macOS BSD grep по умолчанию не поддерживает -P — нужен gnu-grep через Homebrew (brew install grep).

Якоря и классы символов

  • ^pattern — строка начинается с pattern
  • pattern$ — строка заканчивается на pattern
  • ^pattern$ — вся строка ровно pattern
  • [abc] — один из символов a, b или c
  • [^abc] — НЕ a, не b, не c (отрицание класса)
  • [a-z] — диапазон
  • [[:digit:]] — POSIX-класс «цифры»
  • [[:space:]], [[:alnum:]], [[:upper:]] — другие POSIX-классы
# Строки, начинающиеся с timestamp YYYY-MM-DD
$ grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}' app.log

# Не пустые строки и не комментарии
$ grep -Ev '^#|^$' /etc/sshd_config

# IP-адреса (грубо)
$ grep -E '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' access.log

Множественные паттерны: -e и -f

# Несколько паттернов через -e
$ grep -e ERROR -e WARN -e FATAL app.log

# Паттерны из файла (один на строку)
$ cat patterns.txt
ERROR
WARN
FATAL
$ grep -f patterns.txt app.log

-f patterns.txt особенно мощно: можно держать список известных error-keywords в файле и обновлять отдельно от скрипта.

DE-паттерны с grep

1. Топ-10 ошибочных DAG за день

$ grep "Task failed" /var/log/airflow/scheduler.log \
    | awk -F'dag_id=' '{print $2}' \
    | awk -F',' '{print $1}' \
    | sort | uniq -c | sort -rn | head -10
   234 sync_dim_users
    89 load_orders
    45 process_events
    ...

2. Stack trace в Python-приложении (контекст)

$ grep -A 20 "Traceback" app.log    # вывести traceback + 20 строк после

Стандартный Python-traceback занимает 5-15 строк — -A 20 выводит весь, плюс возможный лог-вывод после.

3. Найти конфиг-файлы с устаревшей настройкой

$ grep -rl 'use_legacy_sql' --include='*.cfg' /opt/airflow
/opt/airflow/dags/old_etl/airflow_local_settings.cfg
/opt/airflow/dags/team_a/connection_helper.cfg

--include='*.cfg' сужает recursive search только до .cfg файлов. -l показывает только имена. Удобно когда планируешь rewrite — сразу видишь список целей.

4. Грепнуть в gzip-логах

# Логи часто rotated и gzip'нуты:
$ ls /var/log/airflow/scheduler.log*
scheduler.log
scheduler.log.1
scheduler.log.2.gz
scheduler.log.3.gz

$ zgrep "ERROR" /var/log/airflow/scheduler.log.*.gz | head

zgrep — wrapper, который сам декомпрессирует .gz перед grep. Также есть bzgrep, xzgrep. На современных системах эти команды есть из коробки.

5. ripgrep (rg) — современный grep

# Установка
$ sudo apt install ripgrep   # Ubuntu 26.04
$ brew install ripgrep        # macOS

$ rg ERROR app.log
$ rg -i error app.log           # case insensitive
$ rg 'ERROR|WARN' app.log       # ERE по умолчанию
$ rg -t py 'TODO'               # только .py файлы (type-detect)
$ rg --json PATTERN | jq ...    # structured output

ripgrep (rg) написан на Rust, обходит .gitignore и binary-файлы по умолчанию, использует SIMD для скорости, понимает file types через расширения. На больших codebase в 5-50 раз быстрее grep.

grep vs ripgrep

Когда что использовать. Спойлер: ripgrep почти всегда быстрее и удобнее.

grepPOSIX, есть везде
Скриптыиспользуй grepgrep гарантированно есть в POSIX-окружении, в minimal Docker-образе, на старом RHEL. Зависимость 0.
СкоростьOK на маленьких файлах
Bin/Gitне пропускает binary, не уважает .gitignore
ripgrep (rg)modern, Rust, SIMD
Скриптыосторожно — может не бытьrg надо ставить отдельно. В CI-образе для скрипта не используй — лучше grep -P или GNU awk.
Скоростьв 5-50 раз быстрее на codebase
Bin/Gitпо умолчанию skip .gitignore, skip binary, skip .git/

Скорость grep: фиксированные строки vs regex

Если pattern — просто фиксированная строка без regex-метасимволов, используй -F (fixed string):

$ grep -F '192.168.1.1' access.log
# vs
$ grep '192.168.1.1' access.log
# Второй интерпретирует точки как 'любой символ'!
# Результат: совпадёт и '192a168b1c1', что неверно.

-F (или fgrep) выключает regex parsing — точка остаётся точкой. Быстрее (не строит regex automaton) и семантически корректнее для поиска literal-строк.

Попробуй сам

  1. Создай тестовый лог и поищи в нём:
    cat > /tmp/test.log <<EOF
    2026-05-13 12:34:56 INFO  starting service
    2026-05-13 12:34:57 ERROR connection refused
    2026-05-13 12:34:58 WARN  retrying
    2026-05-13 12:35:01 ERROR timeout
    EOF
    grep ERROR /tmp/test.log
    grep -c ERROR /tmp/test.log
    grep -E '(ERROR|WARN)' /tmp/test.log
  2. Рекурсивный поиск TODO в своём проекте:
    grep -rn TODO ~/Projects 2>/dev/null | head -20
  3. Найти строки с цифрами в начале:
    grep -E '^[0-9]' /etc/group | head
    # Ничего — группы в /etc/group начинаются с букв
  4. Найти конфиги без strict mode:
    grep -L 'set -euo pipefail' /usr/local/bin/*.sh 2>/dev/null
Анализ DNS-логов через grep — dig и nslookup

macOS-различия

  • BSD grep на macOS:
    • Не поддерживает -P (PCRE) — установи brew install grep для GNU-версии (ggrep)
    • Поддерживает -E, -F, -i, -v, -n, -c, -l, -r — то же, что в GNU
    • --include / --exclude есть, поведение немного отличается
  • ripgrep через brew install ripgrep — работает идентично Linux-версии.
Проверка знанийKnowledge check
У тебя есть лог /var/log/api.log в 50 GB. Тебе нужно вывести ТОЛЬКО количество строк, в которых есть слово 'ERROR' (без учёта регистра), и игнорировать строки с 'DEBUG'. Какая команда оптимальна?
ОтветAnswer
grep -ic ERROR /var/log/api.log не сработает напрямую (он включит строки с DEBUG ERROR). Правильно: grep -iv DEBUG /var/log/api.log | grep -ic ERROR. Логика: -i (case-insensitive), -v (инвертировать), -c (только count). Pipeline: сначала отсеять DEBUG-строки, потом посчитать ERROR в остатке. Альтернатива через ERE: grep -Eic '^[^D]*ERROR' (но не работает если ERROR не в начале). Альтернатива через awk одним проходом: awk 'BEGIN{IGNORECASE=1} !/DEBUG/ && /ERROR/ {n++} END {print n}'. На 50 GB awk одним проходом будет быстрее grep + grep двух проходов pipe. ripgrep быстрее обоих благодаря SIMD. Важный нюанс: -c в grep — это число совпавших строк, а не число вхождений pattern (одна строка с двумя ERROR засчитается как одна). Если нужны вхождения — grep -o PATTERN | wc -l.

Главное

  • grep PATTERN FILE — базовый синтаксис; ничего не нашёл -> exit code 1.
  • Ключевые флаги: -i (case), -v (invert), -n (line nums), -c (count), -l (filenames), -r (recursive), -E (extended regex), -F (fixed string).
  • Используй -E для нормального regex или -P для PCRE с lookahead/lookbehind.
  • zgrep для gzip-логов, без явной декомпрессии.
  • ripgrep (rg) — быстрее и удобнее, но не везде есть. В скриптах — POSIX grep.
  • -F для literal-поиска (быстрее и безопаснее regex).
  • -A/-B/-C для контекста — незаменимо для stack-traces.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Команда 'grep ERROR app.log' возвращает exit code 1. Что это значит?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5