Ответы:
grep -l string2 `grep -l string1 /path/*`
который так же, как
grep -l string2 $(grep -l string1 /path/*)
Изменить: вот почему grep string1 /path/* | grep string2не делает то, что я думаю, alwbtc хочет.
$ cd /tmp
$ cat a
apples
oranges
bananas
$ cat b
apples
mangoes
lemons
$ cat c
mangoes
limes
pears
$ cd ~
$ grep apples /tmp/* | grep mangoes
$
Ничего не найдено, но файл b содержит обе строки.
Вот что я думаю, что alwbtc хочет
$ grep -l apples $(grep -l mangoes /tmp/*)
/tmp/b
-lопцию, чтобы обе команды считались равными.
Труба одно grepв другое:
grep "string1" /path/to/files/* | grep "string2"
Вот эквивалент изведКоманда для ответа RedGrittyBrick :
ack string2 $(ack string1 -l)
Работает так же (за исключением того, что ackпо умолчанию ищет текущий каталог рекурсивно). Содержимое в $()поиске, string1но -lвыводит только имена файлов, где была найдена эта строка. Затем они передаются в качестве аргументов во внешнюю команду, что означает, что string2поиск производится только в этом списке файлов.
comm -12 <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort) <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort)
или менее избыточно:
search_files () { str="$1"; shift; grep -Fl "$str" "$@" 2>/dev/null | sort; }
comm -12 <(search_files "STRING1" /path/to/files/*) <(sf "STRING2" /path/to/files/*)
Это будет работать, если строки находятся в разных строках одного и того же файла, а также позволит избежать ложных срабатываний, если имя файла содержит одну из строк.
Чтобы уточнить решение @ RedGrittyBrick, которое имеет недостаток при запуске команды без присмотра, плюс для подавления вывода ошибок по назначению и рекурсивного поиска файлов, вы можете рассмотреть
grep -l 'STRING1' $(! grep -lrs 'STRING2' /absolute/path/to/search/dir && echo /dev/null)
-sопция подавляет сообщения об ошибках;
-rопция позволяет искать строки в произвольно вложенных каталогах в
!сочетании с && echo /dev/nullгарантией того, что команда не будет зависать. В противном случае, если inner grepфайл не найден, он ничего не выведет, так что он outer grepбудет бесконечно ждать ввода для поиска. Это решение выводит /dev/nullв этих случаях так outer grepбудет искать STRING1в /dev/nullкотором он должен ничего не найти.
Я искал расширяемый способ сделать 2 или более строк и придумал это:
grep -rl string1 path-to-files | xargs grep -l string2 | xargs grep -l string3
Первый grep рекурсивно находит имена файлов, содержащихся string1внутри path-to-files.
Результат передается по xargsодной или нескольким командам grep для этих файлов string2.
Затем результаты передаются в другую xargsкоманду для string3- она такая же, как первый xargsвызов, но ищет другую строку.
Использование xargsпозволит избежать проблем, когда результатов будет так много, что полученная командная строка от использования обратных тиков будет слишком длинной.
Чтобы избежать предупреждений, мы можем перенаправить stderrна /dev/null:
grep -rl string1 path-to-files 2>/dev/null | xargs grep -l string2
Это не требуется при последующих вызовах grep, поскольку string1он уже найден внутри файла, поэтому известно, что разрешения хорошие.
-lопцию для возврата имен файлов вместо строк. Затем он использует знак доллара или обратные кавычки, чтобы передать этот список в качествеFILEаргумента во второй grep. Это позволяет второму grep выполнять поиск по всему найденному файлу, а не по отдельным строкам, как в моем решении.