Вопрос: Как игнорировать определенные имена файлов с помощью «find»?


Одна из моих любимых команд BASH:

find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;

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

Однако из-за моего текущего проекта и структуры моей кодовой базы я хотел бы сделать эту команду BASH еще более продвинутой, не просматривая файлы, находящиеся в каталоге или ниже каталога, содержащего «.svn», или любые файлы, которые end с ".html"

Страница MAN для поиска меня путала. Я попытался использовать -prune, и это дало мне странное поведение. В попытке пропустить только страницы .html (для запуска) я попытался:

find . -wholename './*.html' -prune -exec grep 'SearchString' {} /dev/null \;

и не получил того поведения, на которое я надеялся. Я думаю, что, возможно, я пропустил пункт -prune. Могли бы вы, ребята, помочь мне?

благодаря


109
2018-03-05 23:28


Источник


Просто fyi: find не является встроенной командой bash, а отдельной программой - WakiMiko
Вы можете искать внутри файла с помощью grep -rl 'SearchString' - emanuele
@emanuele Привет, добро пожаловать в SuperUser (и сеть обмена стеками). Это вопрос, который я задал, и на это был дан ответ, 2 1/2 года назад. Как правило, если вы хотите добавить ответ на вопрос, пожалуйста, сделайте это, прокрутив ко дну и отвечая туда, а не в комментарии. Поскольку этот вопрос уже имеет принятый ответ (тот, у которого есть зеленая галочка), вряд ли ваш ответ привлечет много внимания. FYI. - Cody S
Привет, это не ответ на ваш вопрос. Это только совет, как вы указали в преамбуле, что использование find для поиска внутри файла. - emanuele
FWIW, -name '*.*' не находит все файлы: только те, у кого есть . от их имени (использование *.* обычно является DOS-ism, тогда как в Unix вы обычно используете только * для этого). Чтобы действительно соответствовать всем этим, просто удалите аргумент в целом: find . -exec ..., Или если вы хотите применить grep к файлам (и пропустить каталоги), тогда выполните find . -type f -exec ..., - Stefan


Ответы:


Вы можете использовать функцию negate (!) Find, чтобы не совпадать с файлами с определенными именами:

find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;

Поэтому, если имя заканчивается на .html или содержит .svn в любом месте пути, оно не будет соответствовать, и поэтому exec не будет выполнен.


156
2018-03-06 00:40



Должен ли я указывать -name ',«Где-то там? Я сделал бы это раньше или после отрицаний? - Cody S
Было ли ваше намерение *.* чтобы обеспечить соответствие только файлов, содержащих .? Поиск будет соответствовать всем файлам в отсутствие name директива, поэтому выше будет соответствовать все, кроме html и svn - Paul
Я думаю, ты хочешь -wholename '*.svn*' скорее, чем -name, - fuenfundachtzig
Да, это так, .svn каталоги исключаются из результатов поиска. - fuenfundachtzig
@Noumenon ! -name '.' следует исключить . из результатов поиска. - Paul


У меня была такая же проблема в течение длительного времени, и есть несколько решений, которые могут быть применимы в разных ситуациях:

  • ack-grep это своего рода «разработчик» grep" который по умолчанию пропускает каталоги управления версиями и временные файлы. man на странице объясняется, как искать только определенные типы файлов и как определить свои собственные,
  • grepсобственная --exclude а также --exclude-dir параметры могут использоваться очень легко, чтобы пропустить файл шарики а также Один каталогов (к сожалению, нет подтасовки для каталогов).
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -prune -o -print0 | xargs -0 grep ... должен работать, но вышеупомянутые варианты, вероятно, менее сложны в долгосрочной перспективе.

9
2018-03-06 13:54





Следующие find команда отменяет каталоги, чьи имена содержать  .svn, Хотя он не спускается в каталог, имя обрезанного пути печатается ... (-name '*.svn' это причина!) ..

Вы можете отфильтровать имена каталогов через: grep -d skip который молча пропускает такие входные «имена каталогов».

С GNU grep вы можете использовать -H вместо /dev/null, Как небольшой побочный вопрос: \+ может быть намного быстрее, чем \;, например. для 1 миллиона однострочных файлов, используя \; это заняло 4m20s, с помощью \+ это заняло 1.2s,

Следующий метод использует xargs вместо -exec, и предполагает, что нет новых строк \n в любом из ваших файлов имена, Как используется здесь, xargs это то же самое, что найти \+,

xargs могут передавать имена файлов, которые содержат последовательные пробелы, изменяя входной разделитель на '\n' с -d вариант.

Это исключает каталоги, чьи имена содержать  .svn и grep только файлы, которые не заканчиваются .html,

find . \( -name '*.svn*' -prune  -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'

7
2018-03-06 03:29



Спасибо, что указали \+ вариант действия -exec. Ура для незначительных проблем! - Christian Long
Конечно, поскольку + не является особым символом для оболочки, вам не нужно вводить \ перед этим. - Scott