Piping находит результаты в grep для быстрого исключения каталогов

Я успешно использую find для создания списка всех файлов в текущем подкаталоге, за исключением тех, которые находятся в кэш-памяти подкаталога. Вот мой первый бит кода:

find . -wholename './cach*' -prune -o -print

Теперь я хочу передать это в команду grep. Похоже, это должно быть простым:

find . -wholename './cach*' -prune -o -print | xargs grep -r -R -i "samson"

... но это возвращает результаты, которые в основном из каталога кеша. Я попытался удалить ссылку xargs, но это делает то, что вы ожидаете, запуская grep по тексту имен файлов, а не по самим файлам. Моя цель - найти "samson" в любых файлах, которые не кэшируются.

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

(Это в CentOS 5, кстати.)

Ответ 1

Соответствие wholename может быть причиной, по которой оно все еще включает файлы "cache". Если вы выполняете команду find в каталоге, который содержит папку "cache", он должен работать. Если нет, попробуйте заменить его на -name '*cache*'.

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

Вы можете обновить свою команду, используя версию с поддержкой протокола или одну команду:

find . -name '*cache*' -prune -o -print0 | xargs -0 grep -il "samson"

или

find . -name '*cache*' -prune -o -exec grep -iq "samson" {} \; -print

Примечание. -l в первой команде сообщает grep "перечислить файл", а не соответствующую строку (строки). -q во втором делает то же самое; он сообщает grep ответить тихо, поэтому find будет просто печатать имя файла.

Ответ 2

Используйте параметр -exec для поиска вместо того, чтобы связывать их с другой командой. Оттуда вы можете использовать grep "samson" {} \; для поиска samson в каждом указанном файле.

Например:

find . -wholename './cach*' -prune -o -exec grep "samson" "{}" +

Ответ 3

Вы сказали grep самому себе: (дважды! -r и -r являются синонимами). Поскольку один из аргументов, которые вы передаете, . (верхний каталог), grep выполняет поиск в каждом файле (некоторые из них дважды или даже больше, если они находятся в подкаталогах).

Если вы собираетесь использовать find и grep, сделайте следующее:

find . -path './cach*' -prune -o -print0 | xargs -0 grep -i "samson"

Используя -print0 и -0, ваш script работает даже с именами файлов, которые содержат пробелы или знаки пунктуации.

Однако вам, вероятно, не нужно беспокоиться о find здесь, поскольку GNU grep способен исключать каталоги:

grep -R --exclude-dir='cach*' -i "samson" .

(Это также исключает ./deeply/nested/directory/cache. Если вы хотите только исключить каталоги кешей на верхнем уровне, используйте find, как и вы.)