CLI AI

Рекурсивный grep с исключением каталога

2026-06-08

grep -rn --exclude-dir={.git,node_modules,vendor} 'TODO' . находит все совпадения, пропуская три каталога, которые портят почти любой рекурсивный grep в реальном репозитории. --exclude-dir работает только вместе с -r и сравнивает голое имя каталога, а не путь. Дальше — весь рецепт: от наивного рекурсивного поиска до момента, когда проще поставить ripgrep.

1. Искать по всему проекту

clai
$ clai найди TODO во всех файлах внутри g→ grep -rn 'TODO' g/g/src/a.js:1:TODO fixg/node_modules/b.js:1:TODO dep

-r рекурсивно, -n добавляет номер строки. Проблема видна сразу: половина находок из чужого кода.

2. Исключить один каталог

clai
$ clai найди TODO, но не заглядывай в node_modules→ grep -rn --exclude-dir=node_modules 'TODO' g/g/src/a.js:1:TODO fix

--exclude-dir работает только вместе с -r. Имя каталога указывается без слешей — это шаблон имени, а не путь.

3. Исключить сразу несколько

clai
$ clai найди TODO, пропусти node_modules, .git и vendor→ grep -rn --exclude-dir={.git,node_modules,vendor} 'TODO' .

Фигурные скобки разворачивает оболочка ещё до запуска grep — он получит три отдельных флага. В sh без поддержки brace expansion придётся писать три --exclude-dir подряд.

4. Искать только в нужных файлах

clai
$ clai найди TODO только в javascript-файлах→ grep -rn --include='*.js' 'TODO' .

--include это белый список. Когда вы знаете, где искать, он и короче, и быстрее длинной цепочки исключений.

5. Не спотыкаться о бинарники

clai
$ clai найди TODO, игнорируя бинарные файлы→ grep -rnI 'TODO' .

Без -I grep на бинарном файле печатает «Binary file … matches» вместо строки — это засоряет вывод и ломает разбор результата скриптом. -I просто пропускает такие файлы.

6. Когда флагов становится слишком много

clai
$ clai найди TODO в проекте, уважая gitignore→ rg 'TODO'

ripgrep по умолчанию читает .gitignore, пропускает .git и бинарники — то есть делает всё вышеперечисленное без единого флага, и быстрее. Если вы третий раз за день пишете длинную цепочку --exclude-dir, пора его поставить.

Грабли

  • --exclude-dir без -r молча ничего не делает. Флаг принимается, но не применяется, и вы решите, что он не работает.
  • Шаблон в --exclude-dir не путь. --exclude-dir=src/vendor не сработает, потому что сравнивается имя каталога, а не путь до него. Пишите --exclude-dir=vendor.
  • Кавычки вокруг шаблона обязательны. grep -r --include=*.js оболочка развернёт по файлам текущего каталога до запуска grep, и вы получите совсем не тот поиск.

Похожие вопросы

Как исключить сам каталог .git? --exclude-dir=.git. Точка в начале имени ничего не меняет, а вот -r по репозиторию без этого флага выдаёт мусор из объектов git.

Как посчитать совпадения, а не показать их? grep -rc 'TODO' . печатает счётчик по каждому файлу, grep -rho 'TODO' . | wc -l — общее число вхождений.

grep или ripgrep? grep есть везде и его надо знать. ripgrep быстрее и по умолчанию делает разумные вещи, но его надо ставить, а на чужом сервере это не всегда возможно.

Читайте также

Не запоминайте флаги исключений — опишите, что ищете, а grep напишет CliAI. Установка одной строкой.