Команда Unix для вывода списка файлов, содержащих строку, но * NOT *, содержащих другую строку - PullRequest
30 голосов
/ 14 февраля 2011

Как мне рекурсивно просмотреть список файлов, которые имеют одну строку и, в частности, не имеют другой строки?Кроме того, я хочу оценить текст файлов, а не имена файлов.


Заключение:

В соответствии с комментариями, я в итоге использовал:

find . -name "*.html" -exec grep -lR 'base\-maps' {} \; | xargs grep -L 'base\-maps\-bot'

Это вернуло файлы с «base-maps», а не «base-maps-bot».Спасибо !!

Ответы [ 5 ]

42 голосов
/ 14 февраля 2011

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

grep -rl <string-to-match> | xargs grep -L <string-not-to-match>

Объяснение: grep -lr заставляет grep рекурсивно (r) выводить список (l) всех файлов, которые содержат <string-to-match>. xargs перебирает эти файлы, вызывая grep -L для каждого из них. grep -L выведет имя файла только тогда, когда файл не содержит <string-not-to-match>.

3 голосов
/ 18 августа 2014

Использование xargs в ответах выше не обязательно;вы можете добиться того же, что и в этом случае:

find . -type f -exec grep -q <string-to-match> {} \; -not -exec grep -q <string-not-to-match> {} \; -print

grep -q означает «бежать спокойно», но возвращает код выхода, указывающий, было ли найдено совпадение;find может затем использовать этот код завершения, чтобы определить, следует ли продолжать выполнение остальных его параметров.Если -exec grep -q <string-to-match> {} \; вернет 0, то он продолжит выполнение -not -exec grep -q <string-not-to-match>{} \;.Если он также возвращает 0, он будет продолжать выполнять -print, который печатает имя файла.

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

1 голос
/ 09 апреля 2014

Вот более общая конструкция:

find . -name <nameFilter> -print0 | xargs -0 grep -Z -l <patternYes> | xargs -0 grep -L <patternNo>

Эта команда выводит файлы, имена которых совпадают с <nameFilter> (отрегулируйте предикаты find по мере необходимости), которые содержат <patternYes>, но не содержат <patternNo>.

Улучшения:

  • Работает с именами файлов, содержащими пробелы.
  • Позволяет фильтровать файлы по имени.

Если вам не нужно фильтровать по имени (часто требуется рассмотреть все файлы в текущем каталоге), вы можете удалить find и добавить -R к первому grep:

grep -R -Z -l <patternYes> | xargs -0 grep -L <patternNo>
1 голос
/ 19 февраля 2011

Эти ответы выглядят как совпадающие ОБА строки. Следующая команда должна работать лучше:

grep -l <string-to-match> * | xargs grep -c <string-not-to-match> | grep '\:0'
0 голосов
/ 21 мая 2019

найти. -maxdepth 1 -name "* .py" -exec grep -L "строка не соответствует" {} \;

Эта команда получит все ".py" файлы, которые не содержат "string-not-to-match" в одном каталоге.

...