Используйте синтаксис grep --exclude / - include, чтобы не просматривать определенные файлы

780

Я ищу строку foo=в текстовых файлах в дереве каталогов. Это на обычной машине Linux, у меня есть оболочка bash:

grep -ircl "foo=" *

В каталогах также много бинарных файлов, которые соответствуют "foo =". Поскольку эти результаты не релевантны и замедляют поиск, я хочу, чтобы grep пропустил поиск этих файлов (в основном изображений JPEG и PNG). Как бы я это сделал?

Я знаю , что существуют --exclude=PATTERNи --include=PATTERNварианты, но то , что это формат картины? Страница руководства grep гласит:

--include=PATTERN     Recurse in directories only searching file matching PATTERN.
--exclude=PATTERN     Recurse in directories skip file matching PATTERN.

Поиск по grep include , grep include exclude , grep exclude и варианты не нашли ничего подходящего

Если есть лучший способ поиска только в определенных файлах, я за все; перемещение оскорбительных файлов не вариант. Я не могу искать только определенные каталоги (структура каталогов - большой беспорядок, со всем везде). Кроме того, я ничего не могу установить, поэтому я имею дело с обычными инструментами (такими как grep или предлагаемый поиск ).

Писквор покинул здание
источник
13
Просто FYI, используемые аргументы: -c подсчитывать совпадения в файле -i без учета регистра -l показывать только совпадающие файлы -r рекурсивно
учета
68
Более быстрый способ исключить svn dirs --exclude-dir=.svn, так что grep не входит в них вообще
orip
25
Пару педантичных моментов, которые люди могут знать: 1. Обратите внимание на отсутствие кавычек вокруг глобуса: --exclude = ' . {Png, jpg}' не работает (по крайней мере, с моей версией GNU grep), потому что grep не поддерживает {} в его глобусах. Вышесказанное расширено до «--exclude = .png --exclude = *. Jpg» (при условии, что в cwd нет совпадений с файлами - очень маловероятно, поскольку вы обычно не начинаете имена файлов с «--exclude =»), что grep любит просто отлично. 2. --exclude является расширением GNU и не является частью определения grep в POSIX, поэтому, если вы пишете сценарии, использующие это, имейте в виду, что они не обязательно будут работать в не-GNU системах.
ijw
2
Полный пример использования exclude-dir:grep -r --exclude-dir=var "pattern" .
Tisch

Ответы:

767

Используйте синтаксис оболочки:

grep pattern -r --include=\*.{cpp,h} rootdir

Синтаксис для --excludeидентичен.

Обратите внимание, что звезду экранируют с помощью обратной косой черты, чтобы предотвратить ее расширение оболочкой (цитирование, например --include="*.{cpp,h}", будет работать так же хорошо). В противном случае, если у вас есть какие-либо файлы в текущем рабочем каталоге, соответствующие шаблону, командная строка будет расширена до чего-то вроде grep pattern -r --include=foo.cpp --include=bar.h rootdir, который будет искать только файлы с именами foo.cppи bar.h, что, скорее всего, не то, что вы хотели.

Адам Розенфилд
источник
8
Я не знаю почему, но мне пришлось процитировать шаблон включения следующим образом:grep pattern -r --include="*.{cpp,h}" rootdir
topek
6
@topek: Хорошая мысль - если у вас есть какие-либо файлы .cpp / .h в вашем текущем каталоге, то оболочка раскроет глобус перед вызовом grep, так что вы получите командную строку, например grep pattern -r --include=foo.cpp --include=bar.h rootdir, которая будет искать только файлы по имени foo.cppили bar.h. Если у вас нет файлов, которые соответствуют глобу в текущем каталоге, то оболочка передает глоб в grep, который правильно его интерпретирует.
Адам Розенфилд
6
Я только что понял, что глобус используется только для соответствия имени файла. Чтобы исключить весь каталог, нужна --exclude-dirопция. Однако применяются те же правила. Совпадает только имя файла каталога, а не путь.
Кшиштоф Яблонский
3
--includeкажется, не работает после --exclude. Я полагаю, что не имеет смысла даже пытаться, за исключением того, что у меня есть aliasgrep с длинным списком --excludeи --exclude-dir, который я использую для поиска кода, игнорирования библиотек и подкачки файлов и прочего. Я бы надеялся , что grep -r --exclude='*.foo' --include='*.bar'будет работать, так что я мог бы ограничить мой , aliasчтобы --include='*.bar'только, но это , кажется, игнорируют --includeи включают в себя все , что это не .foo файл. Менять порядок --includeи --excludeработает, но увы, это не поможет с моим alias.
Майкл Шепер
1
как мы можем читать чьи-то мысли, чтобы получить правила для этого PATTERN. Полчаса я не могу найти описания того, что они там ждут
Аркадий
221

Если вы просто хотите пропустить двоичные файлы, я предлагаю вам взглянуть на -I(верхний регистр). Он игнорирует двоичные файлы. Я регулярно использую следующую команду:

grep -rI --exclude-dir="\.svn" "pattern" *

Он ищет рекурсивно, игнорирует двоичные файлы и не ищет в скрытых папках Subversion какой-либо шаблон, который мне нужен. У меня есть псевдоним "grepsvn" на моей коробке на работе.

rmeador
источник
1
Спасибо, это очень полезно для некоторых других сценариев, с которыми я столкнулся.
Писквор покинул здание
25
--exclude-dirне доступен везде у моего RH box при работе с GNU grep 2.5.1 его нет.
gcb
Любые предложения о том, что использовать, когда --exclude-dirнет в наличии? Во всех моих попытках, похоже, --excludeне отвечает всем требованиям .
JMTyler
Вы всегда можете скачать последнюю версию grep с GNU и выполнить команду 'configure; делать; sudo make install '. Это одна из первых вещей, которую я делаю на Mac или более старом дистрибутиве Linunx.
Джонатан Хартли
3
Именно то, что мне было нужно. На самом деле, я использую Git. Так, --exclude-dir="\.git". :-)
Ионика Бизэ
66

Пожалуйста, обратите внимание на ack , который предназначен именно для этих ситуаций. Ваш пример

grep -ircl --exclude=*.{png,jpg} "foo=" *

делается с Ack как

ack -icl "foo="

потому что ack никогда не просматривает двоичные файлы по умолчанию, а -r включен по умолчанию. И если вы хотите только файлы CPP и H, то просто сделайте

ack -icl --cpp "foo="
Энди Лестер
источник
Выглядит хорошо, попробую автономную версию Perl в следующий раз, спасибо.
Писквор покинул здание
5
Хороший звонок, я больше не могу жить без ack.
шанс
1
stackoverflow.com/questions/667471/… - Это позволит вам получить доступ к окнам, если вы работаете с grep.
TamusJRoyce
@ Шанс Может быть, вы хотите silversearcher-ag , просто apt-getв Ubuntu :)
Justme0
не путать сawk
Джейсон Леонард
35

grep 2.5.3 ввел параметр --exclude-dir, который будет работать так, как вы хотите.

grep -rI --exclude-dir=\.svn PATTERN .

Вы также можете установить переменную окружения: GREP_OPTIONS = "- exclude-dir = .svn"

Я второй голос Энди за кв, хотя, это лучший.

Corey
источник
7
+1 за упоминание точного номера версии; У меня есть grep 2.5.1 и опция exclude-dir недоступна
Джеймс
25

Я обнаружил, что после долгого времени вы можете добавить несколько включений и исключений, таких как:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js
Рашабх Мехта
источник
5
Лучше объединить их в список, например: --exclude = {pattern1, pattern2, pattern3}
Yasser
12

Предлагаемая команда:

grep -Ir --exclude="*\.svn*" "pattern" *

концептуально неверно, потому что --exclude работает с базовым именем. Другими словами, он пропустит только .svn в текущем каталоге.


источник
3
Да, это не работает для меня. Тот, который работал для меня, был: exclude-dir = .svn
Taryn East
2
@ Николя спасибо! Я рвал на себе волосы о том, почему это не сработает. Скажите, есть ли способ узнать это из справочной страницы? Все, что он говорит, это соответствует "УЗОРУ". Редактировать man-страницу говорит "файл", как объяснено здесь fixunix.com/unix/…
13ren
11

В grep 2.5.1 вы должны добавить эту строку в профиль ~ / .bashrc или ~ / .bash

export GREP_OPTIONS="--exclude=\*.svn\*"
эктодермальный
источник
9

Иногда я считаю, что вывод grep очень полезен:

grep -rn "foo=" . | grep -v "Binary file"

Тем не менее, это на самом деле не мешает искать двоичные файлы.

Аарон Маенпаа
источник
10
Вы можете использовать, grep -Iчтобы пропустить двоичные файлы.
Натан Феллман
Я также делал это, когда я был молодым ... теперь я знаю лучше, и когда сталкиваюсь с проблемой, первым делом это
RTFM
grep grep удалит цветные блики.
Макс Ли
7

Если вы не против использования find, мне нравится его -pruneфункция:

find [directory] \
        -name "pattern_to_exclude" -prune \
     -o -name "another_pattern_to_exclude" -prune \
     -o -name "pattern_to_INCLUDE" -print0 \
| xargs -0 -I FILENAME grep -IR "pattern" FILENAME

В первой строке вы указываете каталог, который хотите найти. .(текущий каталог) является допустимым путем, например.

На 2 - й и 3 - й линии, использование "*.png", "*.gif", "*.jpg"и так далее. Используйте как можно больше-o -name "..." -prune конструкций, сколько у вас есть шаблонов.

На 4-й строке вам нужен другой -o(он указывает «или» на find) шаблоны, которые вы НУЖНЫ, и вам нужно либо в конце, -printлибо -print0в конце. Если вы просто хотите «все остальное» , что остается после того, как подрезать *.gif, *.pngи т.д. изображения, а затем использовать , -o -print0и вы сделали с 4 - й линии.

Наконец, на 5-й линии идет труба xargs который берется каждый из этих результирующих файлов и сохраняется их в переменной FILENAME. Затем он проходит grepна -IRфлаги, тем "pattern", а затем FILENAMEрасширяется , xargsчтобы стать , что список имен файлов найденfind .

По вашему конкретному вопросу утверждение может выглядеть примерно так:

find . \
     -name "*.png" -prune \
     -o -name "*.gif" -prune \
     -o -name "*.svn" -prune \
     -o -print0 | xargs -0 -I FILES grep -IR "foo=" FILES

OnlineCop
источник
Одна поправка, которую я бы предложил: включить -falseсразу после каждого, -pruneтак что если вы забыли использовать, -print0или какая-то execкоманда фактически не напечатает файлы, которые вы хотели исключить: -name "*.png" -prune -false -o name "*.gif -prune -false...
OnlineCop
7

На CentOS 6.6 / Grep 2.6.3 я должен использовать это так:

grep "term" -Hnir --include \*.php --exclude-dir "*excluded_dir*"

Обратите внимание на отсутствие знаков равенства «=» ( в противном случае --include, --exclude, include-dirи --exclude-dirигнорируется)

aesede
источник
6

git grep

Использование, git grepкоторое оптимизировано для производительности и направлено на поиск определенных файлов.

По умолчанию он игнорирует двоичные файлы и уважает ваши .gitignore. Если вы не работаете со структурой Git, вы все равно можете использовать ее, передавая --no-index.

Пример синтаксиса:

git grep --no-index "some_pattern"

Дополнительные примеры см .:

kenorb
источник
5

Конечно, я дилетант, но вот как выглядит мой ~ / .bash_profile:

export GREP_OPTIONS = "- orl --exclude-dir = .svn --exclude-dir = .cache --color = auto" GREP_COLOR = '1; 32'

Обратите внимание, что для исключения двух каталогов мне пришлось дважды использовать --exclude-dir.

4D4M
источник
3

Попробуй это:

$ найти. -name "* .txt" -type f -print | файл xargs | grep "foo =" | cut -d: -f1

Основан здесь: http://www.unix.com/shell-programming-scripting/42573-search-files-exclusion-binary-files.html

Gravstar
источник
3
Это не работает с именами файлов с пробелами, но эту проблему легко решить, используя print0 вместо print и добавив опцию -0 в xargs.
Адам Розенфилд
3

Если вы ищете не рекурсивно, вы можете использовать шаблоны glop для соответствия именам файлов.

grep "foo" *.{html,txt}

включает в себя HTML и TXT. Он ищет только в текущем каталоге.

Для поиска в подкаталогах:

   grep "foo" */*.{html,txt}

В подкаталогах:

   grep "foo" */*/*.{html,txt}
Стефан Лоран
источник
3

В каталогах также много бинарных файлов. Я не могу искать только определенные каталоги (структура каталогов - большой беспорядок). Есть ли лучший способ поиска только в определенных файлах?

ripgrep

Это один из самых быстрых инструментов, предназначенных для рекурсивного поиска в текущем каталоге. Он написан на Rust и построен на основе движка Rust для обеспечения максимальной эффективности. Проверьте подробный анализ здесь .

Так что вы можете просто запустить:

rg "some_pattern"

Он уважает вас .gitignoreи автоматически пропускает скрытые файлы / каталоги и двоичные файлы.

Вы все еще можете настроить включение или исключение файлов и каталогов, используя -g/ --glob. Правила .gitignoreGlobbing соответствуют шарам. Проверьте man rgна помощь.

Дополнительные примеры см .: Как исключить некоторые файлы, не соответствующие определенным расширениям, с помощью grep?

На macOS вы можете установить через brew install ripgrep.

kenorb
источник
3

найди и xargs твои друзья. Используйте их для фильтрации списка файлов, а не grep --exclude

Попробуйте что-то вроде

find . -not -name '*.png' -o -type f -print | xargs grep -icl "foo="

Преимущество привыкания к этому заключается в том, что его можно использовать в других случаях, например, для подсчета строк во всех файлах, отличных от png:

find . -not -name '*.png' -o -type f -print | xargs wc -l

Чтобы удалить все не-PNG файлы:

find . -not -name '*.png' -o -type f -print | xargs rm

и т.п.

Как указано в комментариях, если некоторые файлы могут иметь пробелы в именах, используйте -print0и xargs -0вместо.

Эндрю Стейн
источник
1
Это не работает с именами файлов с пробелами, но эту проблему легко решить, используя print0 вместо print и добавив опцию -0 в xargs.
Адам Розенфилд
2

эти сценарии не решают всех проблем ... Попробуйте это лучше:

du -ha | grep -i -o "\./.*" | grep -v "\.svn\|another_file\|another_folder" | xargs grep -i -n "$1"

этот скрипт лучше, потому что он использует "настоящие" регулярные выражения, чтобы избежать поиска каталогов. просто отдельные имена папок или файлов с помощью "\ |" на grep -v

наслаждайся этим! нашел на моей оболочке linux! XD


источник
2

Смотри @ этот.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags
Suhas Tawade
источник
2
Вещи, которые достигают приблизительно этого, были рассмотрены в других сообщениях; более того, это неправильно, так как при различных настройках макета он будет портить номера строк и тому подобное или исключать нужные строки контекста.
Крис Морган
как вы можете использовать несколько опций "-v" одновременно?
Открой путь
1

--binary-files=without-matchВариант GNU grepполучает его пропустить двоичные файлы. (Эквивалентно -Iпереключателю, упомянутому в другом месте.)

(Для этого может потребоваться последняя версия grep; как минимум, у 2.5.3.)

MJS
источник
1

подходит для tcsh .alias файла:

alias gisrc 'grep -I -r -i --exclude="*\.svn*" --include="*\."{mm,m,h,cc,c} \!* *'

Мне понадобилось время, чтобы понять, что часть {mm, m, h, cc, c} НЕ должна быть в кавычках. ~ Keith

Кит Кнаубер
источник
0

Чтобы игнорировать все двоичные результаты от grep

grep -Ri "pattern" * | awk '{if($1 != "Binary") print $0}'

Часть awk отфильтрует все строки двоичного файла foo match

lathomas64
источник
-2

Попробуй это:

  1. Создайте папку с именем « --F» под currdir .. (или связать другую папку там переименованную « --F» то есть double-minus-F.
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
P Stack
источник