119

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

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

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

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

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

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

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

Спасибо

3 ответа3

167

Вы можете использовать отрицание (!) Особенность поиска не совпадает с файлами с конкретными именами:

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

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

10

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

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

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

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

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

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

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

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

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .