Використовуйте grep --exclude / - включайте синтаксис, щоб не проглядати певні файли


780

Я шукаю рядок foo=у текстових файлах у дереві каталогів. Це на звичайній машині Linux, у мене є bash shell:

grep -ircl "foo=" *

У каталогах також багато двійкових файлів, які відповідають "foo =". Оскільки ці результати не є релевантними та сповільнюють пошук, я хочу, щоб греп пропустив пошук цих файлів (в основному зображення 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 включають , grep включають виключення , grep виключення та варіанти не знайшли нічого релевантного

Якщо є кращий спосіб прив’язання лише до певних файлів, я все за це; переміщення образливих файлів - це не варіант. Я не можу шукати лише певні каталоги (структура каталогів - це безлад, з усім, що скрізь є). Крім того, я нічого не можу встановити, тому мені доводиться робити звичайні інструменти (наприклад, grep або запропоновану знахідку ).


13
Тільки FYI, що використовуються аргументи: -c підраховує відповідність у файлі -i нечутливий до регістру-я показую лише файли, що відповідають, -r рекурсивний
Piskvor покинув будівлю

68
Більш швидкий спосіб виключити svn dirs є --exclude-dir=.svn, тому греп взагалі не входить у них
orip

25
Пару педантичних моментів, можливо, люди повинні знати: 1. Зверніть увагу на відсутність лапок по всьому світу: --exclude = ' . {Png, jpg}' не працює (принаймні, з моєю версією GNU grep), оскільки grep не підтримує {} у своїх глобусах. Наведене вище оболонки розширено на '--exclude = .png --exclude = *. Jpg' (якщо припустимо, що файли не збігаються в cwd - дуже малоймовірно, оскільки ви зазвичай не починаєте назви файлів з '--exclude ='), який греп любить просто чудово. 2. --exclude - це розширення GNU і не є частиною визначення POSIX щодо grep, тому якщо ви пишете сценарії, використовуючи це, пам’ятайте, що вони не обов'язково працюватимуть у системах, що не належать до GNU.
ijw

2
Повний приклад використання виключення режиму: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. Якщо у поточному каталозі у вас немає жодного файлу, який би відповідав глобулю, оболонка передається на глобус в греп, який інтерпретує його правильно.
Адам Розенфілд

6
Я щойно зрозумів, що глобус звик відповідати лише імені файлу. Для виключення цілого каталогу потрібен --exclude-dirваріант. Однак застосовуються ті самі правила. Збігається лише ім'я файлу каталогів, а не шлях.
Кшиштоф Яблонський

3
--includeсхоже, не працює після --exclude. Я вважаю, що не має сенсу навіть намагатися, за винятком того, що я маю aliasпоздоровитись з довгим списком --excludeі --exclude-dir, який я використовую для пошуку коду, ігноруючи бібліотеки та міняючи файли та речі. Я б сподівався , що grep -r --exclude='*.foo' --include='*.bar'буде працювати, так що я міг би обмежити мій , aliasщоб --include='*.bar'тільки, але це , здається, ігнорують --includeі включають в себе всі , що це не .foo файл. Міняючи порядок --includeі --excludeпрацює, але, на жаль, це не корисно для мого alias.
Майкл Шепер

1
як ми можемо прочитати чиюсь думку, щоб отримати для цього правила PATTERN. Півгодини я не можу знайти жодного опису того, що вони там чекають
Аркадій

221

Якщо ви просто хочете пропустити бінарні файли, пропоную переглянути -Iваріант (верхній регістр i). Він ігнорує двійкові файли. Я регулярно використовую таку команду:

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

Він шукає рекурсивно, ігнорує двійкові файли та не зазирає в приховані папки Subversion, за будь-яким шаблоном, який я хочу. У мене це як "grepsvn" на моїй коробці на роботі.


1
Дякую, це дуже корисно для деяких інших сценаріїв, з якими я стикався.
Пісквор вийшов з будівлі

25
--exclude-dirдоступний не скрізь. у моєї коробки RH при роботі з GNU grep 2.5.1 його немає.
gcb

Будь-які пропозиції, що використовувати, коли --exclude-dirнемає? У всіх моїх спробах, --excludeздається, не підходить до рахунку.
JMTyler

Ви завжди можете завантажити останнє джерело grep з GNU та виконати конфігурацію; зробити; sudo make install '. Це одне з перших речей, які я роблю на Mac або старіших дистрибутивах Linunx.
Джонатан Хартлі

3
Саме те, що мені було потрібно. Власне, я використовую git. Так, --exclude-dir="\.git". :-)
Ionică Bizău

66

Погляньте, будь ласка, на ack , який призначений саме для цих ситуацій. Ваш приклад

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

робиться з ack як

ack -icl "foo="

тому що ack ніколи не шукає у двійкових файлах за замовчуванням, а -r увімкнено за замовчуванням. А якщо ви хочете лише файли CPP та H, тоді просто робіть

ack -icl --cpp "foo="

Виглядає приємно, спробую окрему версію Perl наступного разу, дякую.
Пісквор вийшов з будівлі

5
Добрий дзвінок, я вже не можу жити без ака.
Шанс

1
stackoverflow.com/questions/667471/… - Це дозволить вам отримати доступ до Windows, якщо саме там ви працюєте з grep.
TamusJRoyce

@Chance Можливо, ви хочете silversearcher-ag , просто apt-getв Ubuntu :)
Justme0

не плутатиawk
Jasonleonhard

35

grep 2.5.3 представив параметр --exclude-dir, який буде працювати так, як вам потрібно.

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

Ви також можете встановити змінну середовища: GREP_OPTIONS = "- виключити-dir = .svn"

Я другий Енді голосувати за ACK , хоча, це найкраще.


7
+1 для згадування точного номера версії; У мене grep 2.5.1, і опція виключення-dir недоступна
Джеймс

25

Я виявив це через тривалий час, ви можете додати кілька включень і виключень, як:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js

5
Краще поєднати їх у такому списку, як: --exclude = {pattern1, pattern2, pattern3}
Yasser Sinjab

12

Пропонована команда:

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

концептуально неправильно, тому що --exclude працює над базовою назвою. Іншими словами, він пропустить лише .svn у поточному каталозі.


3
Так, для мене це зовсім не працює. Той, хто працював на мене, був: виключити-dir = .svn
Taryn East

2
@Nicola дякую! Я рвав волосся, чому це не вийде. Скажіть, чи є спосіб виявити це на сторінці сторінки? Все, що говорить, відповідає "ПАТЕРНУ". На сторінці редагування EDIT написано "файл", як пояснено тут fixunix.com/unix/…
13

11

У програмі grep 2.5.1 вам потрібно додати цей рядок до профілю ~ / .bashrc або ~ / .bash

export GREP_OPTIONS="--exclude=\*.svn\*"

9

Я вважаю, що вихідні дані grep дуже корисні часом:

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

Хоча це насправді не перешкоджає пошуку бінарних файлів.


10
Ви можете використовувати grep -Iдля пропуску двійкових файлів.
Натан Фелман

також зробив це, коли я був молодим ... тепер я знаю краще і коли
стикаюся

притискання 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


Я б запропонував одну поправку: включити -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ігнорується)


6

git grep

Використання, git grepяке оптимізоване для продуктивності та спрямоване на пошук певних файлів.

За замовчуванням він ігнорує двійкові файли і шанує ваш .gitignore. Якщо ви не працюєте зі структурою Git, ви все одно можете використовувати її, передаючи її --no-index.

Приклад синтаксису:

git grep --no-index "some_pattern"

Більше прикладів див:


5

Я дилетант, наданий, але ось як виглядає мій ~ / .bash_profile:

експортувати GREP_OPTIONS = "- orl --exclude-dir = .svn --exclude-dir = .cache --color = auto" GREP_COLOR = '1; 32'

Зауважте, що для виключення двох каталогів мені довелося використовувати --exclude-dir двічі.


3

Спробуйте це:

$ знайти. -name "* .txt" -типу f -принт | файл xargs | grep "foo =" | вирізати -d: -f1

Заснований тут: http://www.unix.com/shell-programming-scripting/42573-search-files-excluding-binary-files.html


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

3

Якщо ви шукаєте нерекурсивно, ви можете використовувати шаблони глоп для відповідності назви файлів.

grep "foo" *.{html,txt}

включає html та txt. Він здійснює пошук лише в поточному каталозі.

Для пошуку в підкаталогах:

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

У підкаталогах:

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

3

У каталогах також багато двійкових файлів. Я не можу шукати лише певні каталоги (структура каталогів - це безлад). Чи є кращий спосіб прив’язання лише до певних файлів?

ripgrep

Це один з найшвидших інструментів, призначений для рекурсивного пошуку у вашому поточному каталозі. Це написано в Rust , побудованому на вершині двигуна Rgex для максимальної ефективності. Перевірте детальний аналіз тут .

Отже, ви можете просто запустити:

rg "some_pattern"

Він поважає ваші .gitignoreта автоматично пропускає приховані файли / каталоги та бінарні файли.

Ви все ще можете налаштувати включати або виключати файли та каталоги за допомогою -g/ --glob. Правила глобалізації відповідають .gitignoreглобусам. Зверніться man rgза допомогою.

Щоб отримати додаткові приклади, див: Як виключити деякі файли, які не відповідають певним розширенням grep?

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


3

Знайдіть і xargs - ваші друзі. Використовуйте їх для фільтрування списку файлів, а не grep's --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 замість друку та додавши параметр -0 до xargs.
Адам Розенфілд

2

ці сценарії не вирішують усі проблеми ... Спробуйте це краще:

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

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

насолоджуйся цим! знайдено в моїй linux оболонці! XD


2

Подивіться @ цей.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags

2
Речі, які приблизно цього досягають, висвітлювалися в інших посадах; Більше того, це неправильно, оскільки в різних встановлених варіантах компонування воно буде псувати номери рядків і подібні речі або виключати бажані рядки контексту.
Кріс Морган

як можна одночасно використовувати кілька варіантів "-v"?
Відкрийте шлях

1

Можливість --binary-files=without-matchGNU grepотримує його для пропускання бінарних файлів. (Еквівалентно -Iкомутатору, який згадується в іншому місці)

(Для цього може знадобитися остання версія grep; принаймні, в 2.5.3 є.)


1

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

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

Зайняв деякий час, щоб зрозуміти, що частина {mm, m, h, cc, c} НЕ повинна бути всередині лапок. ~ Кіт


0

Ігнорувати всі бінарні результати від grep

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

Частина awk відфільтрує всі рядки бінарного файлу foo, які відповідають строкам


-2

Спробуйте це:

  1. Створіть папку з назвою " --F" під currdir .. (або зв’яжіть іншу папку, там перейменовану на " --F", тобто double-minus-F.
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.