grep
Поиск строк по шаблону в файлах и выводе команд
grep читает файлы (или стандартный ввод) построчно и печатает строки, в которых нашёлся шаблон. Шаблон — регулярное выражение или, с -F, обычная строка. В песочнице — GNU grep 3.11.
Синтаксис
grep [опции] 'шаблон' [файл…]
grep [опции] -e 'шаблон1' -e 'шаблон2' [файл…]
команда | grep [опции] 'шаблон'
Без файлов grep читает stdin (с -r — текущий каталог). Файл - тоже означает stdin.
Код возврата: 0 — нашлась хотя бы одна строка, 1 — ничего не нашлось, 2 — ошибка (нет файла, неверная регулярка). С -q при найденном совпадении будет 0, даже если какой-то файл прочитать не удалось.
Опции
Как понимать шаблон
| Опция | Что делает |
|---|---|
-G | базовые регулярки (BRE) — режим по умолчанию |
-E | расширенные регулярки (ERE): + ? | ( ) { } без обратных слэшей |
-F | шаблон — обычная строка, никаких спецсимволов |
-P | Perl-регулярки (PCRE): \d, \s, ленивые *?, просмотр (?=…), \K |
-e шаблон | задать шаблон; можно повторять — совпадение с любым. Нужен, если шаблон начинается с - |
-f файл | взять шаблоны из файла, по одному на строку |
-i | без учёта регистра; --no-ignore-case — отменить |
-w | шаблон должен совпасть с целым словом (слово — буквы, цифры, _) |
-x | шаблон должен совпасть со всей строкой целиком |
-v | выбрать строки, где совпадения нет |
Что и как печатать
| Опция | Что делает |
|---|---|
-c | вместо строк — их число (совпавших строк, не совпадений), для каждого файла |
-l / -L | только имена файлов, где совпадение есть / где его нет |
-o | только совпавшие фрагменты, каждый на отдельной строке |
-q | ничего не печатать, только код возврата; останавливается на первом совпадении |
-n | номер строки перед строкой: 12:текст |
-b | смещение в байтах от начала файла |
-H / -h | печатать / не печатать имя файла перед строкой. По умолчанию имя есть, если файлов больше одного (или -r) |
-m N | остановиться после N совпавших строк в каждом файле |
-s | не сообщать о несуществующих и нечитаемых файлах |
--color=auto | подсвечивать совпадения (always — даже в конвейере) |
--line-buffered | сбрасывать вывод после каждой строки — нужно в tail -f … | grep … |
-Z | после имени файла ставить нулевой байт (для xargs -0) |
-T | выравнивать вывод табуляцией после префиксов |
--label=имя | имя, которое показывать для stdin |
Контекст
| Опция | Что делает |
|---|---|
-A N | показать ещё N строк после совпадения |
-B N | показать N строк до совпадения |
-C N / -N | N строк до и после (-2 — то же, что -C 2) |
--group-separator=STR / --no-group-separator | чем разделять группы контекста (по умолчанию --) / не разделять |
Файлы и каталоги
| Опция | Что делает |
|---|---|
-r | искать рекурсивно в каталогах; символические ссылки внутри не открывает |
-R | то же, но идёт по всем символическим ссылкам |
--include='*.conf' | смотреть только файлы, подходящие под маску (можно повторять) |
--exclude='*.log' | пропускать файлы по маске |
--exclude-dir=.git | не заходить в каталоги по маске |
-a | считать двоичный файл текстом и печатать совпавшие строки |
-I | молча пропускать двоичные файлы |
-z | строки разделены нулевым байтом, а не \n (для вывода find -print0) |
Формат вывода
Строка вывода собирается из префиксов: имя_файла:номер:смещение:текст. Строки контекста (-A/-B/-C) отделяются не :, а - (app.log-14-текст), а между несмежными группами печатается --.
Примеры
printf 'INFO start\nERROR disk full\nWARN slow\nerror retry\nINFO stop\n' > app.log
# строки с error в любом регистре, с номерами
grep -in error app.log
# всё, кроме строк INFO
grep -v INFO app.log
# несколько шаблонов: через -E и | или через несколько -e
grep -E 'ERROR|WARN' app.log
grep -e ERROR -e WARN app.log
# шаблоны из файла
printf 'ERROR\nWARN\n' > patterns.txt
grep -f patterns.txt app.log
# сколько строк совпало и сколько всего вхождений
grep -ci error app.log
grep -oi error app.log | wc -l
# контекст: строка WARN, одна до и одна после
grep -C1 WARN app.log
# точка как точка, а не «любой символ»
printf 'v1.2.3\nv1x2y3\n' | grep -F '1.2.3'
# целое слово и целая строка
printf 'cat\ncatalog\nthe cat\n' | grep -w cat
printf 'cat\ncatalog\nthe cat\n' | grep -x cat
# рекурсивно: только *.conf, без каталога .git, только имена файлов
grep -rl --include='*.conf' --exclude-dir=.git 'listen' /etc
# в условии скрипта
if grep -q '^ERROR' app.log; then echo 'есть ошибки'; fi
# значение после ключа: \K отбрасывает всё, что совпало до него
echo 'port=8080' | grep -oP 'port=\K\d+'
# только первое совпадение
grep -m1 INFO app.log
# имена файлов с совпадениями — безопасно для xargs
grep -rlZ 'listen' /etc/nginx | xargs -0 ls -l
Подводные камни
-cсчитает строки, а не совпадения. В строкеerror errorбудет 1. Каждое вхождение считай черезgrep -o … | wc -l.ps aux | grep nginxнаходит и самgrep. Возьми одну букву в скобки —grep '[n]ginx': шаблон по-прежнему совпадает сnginx, но строка запуска самого grep ([n]ginx) уже не подходит. Ещё проще — pgrep.- Базовые регулярки (без
-E) понимают+ ? | ( ) { }буквально.grep 'a+b'ищет строкуa+b. Пишиgrep -E 'a+b'илиgrep 'a\+b'. Подробнее — Регулярные выражения. \dи\tработают только с-P. Без него\d— это просто букваd, а\t— букваt. Для цифр есть[0-9]или[[:digit:]], табуляцию можно передать как$'\t'.- Шаблон без кавычек раскроет оболочка:
*,?,[…]и$могут измениться ещё до запуска grep. Бери шаблон в одинарные кавычки. -rне ходит по символическим ссылкам внутри каталога,-R— ходит. Маски--includeи--excludeтоже бери в кавычки.- Двоичные файлы. Если в файле есть нулевые байты, grep напишет
binary file matchesвместо строки.-aпокажет строки,-Iпропустит такие файлы. -oс-cвсё равно считает строки, а-oвместе с-vничего не печатает.- Локаль. В песочнице локаль
POSIX, поэтому-iне сравнивает русские буквы без учёта регистра (Приветиприветразличаются), а.совпадает с одним байтом, а не с кириллической буквой. СLC_ALL=C.utf8оба случая работают как ожидается.