Відповіді:
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
Перший греп рекурсивно знаходить назви файлів, що містяться 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аргумент у другу позицію. Це дозволяє другому грепу шукати весь файл кожного знайденого замість окремих рядків, як у моєму рішенні.