Как найти файлы, содержащие две строки вместе в Linux?

11

Я хочу найти файлы, содержащие две строки вместе, например, файл содержит оба string1и string2.

Я хочу полный путь файлов в выводе. Я не хочу видеть предупреждения "отказано в разрешении".

alwbtc
источник

Ответы:

15
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
RedGrittyBrick
источник
1
Это аккуратное решение и более полезное, чем мое. Для тех, кто хочет знать, что здесь происходит (мне понадобилось немного времени, чтобы выяснить это), он использует -lопцию для возврата имен файлов вместо строк. Затем он использует знак доллара или обратные кавычки, чтобы передать этот список в качестве FILEаргумента во второй grep. Это позволяет второму grep выполнять поиск по всему найденному файлу, а не по отдельным строкам, как в моем решении.
embedded.kyle
Вы пропустили -lопцию, чтобы обе команды считались равными.
Понг
2

Труба одно grepв другое:

grep "string1" /path/to/files/* | grep "string2"

embedded.kyle
источник
5
Если две строки находятся в разных строках файла, это не сработает.
RedGrittyBrick
1
Я не знал, что для них требовалось быть в одной строке @RedGrittyBrick
slhck
@slhck: я обновил свой ответ, чтобы показать, чего, по-моему, хочет alwbtc и почему этот ответ этого не делает. Конечно, я, возможно, неправильно понял, что хочет alwbtc, и встраиваемый. Kyle, возможно, понял это правильно - хотя я подозреваю, что нет.
RedGrittyBrick
1

Вот эквивалент Команда для ответа RedGrittyBrick :

ack string2 $(ack string1 -l)

Работает так же (за исключением того, что ackпо умолчанию ищет текущий каталог рекурсивно). Содержимое в $()поиске, string1но -lвыводит только имена файлов, где была найдена эта строка. Затем они передаются в качестве аргументов во внешнюю команду, что означает, что string2поиск производится только в этом списке файлов.

congusbongus
источник
0
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/*)

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

user381521
источник
0

Чтобы уточнить решение @ 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котором он должен ничего не найти.

понг
источник
0

Я искал расширяемый способ сделать 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он уже найден внутри файла, поэтому известно, что разрешения хорошие.

awatts
источник