Odpowiedzi:
grep -l string2 `grep -l string1 /path/*`
który jest taki sam jak
grep -l string2 $(grep -l string1 /path/*)
Edycja: oto dlaczego grep string1 /path/* | grep string2nie robi tego, co myślę, że chce alwbtc.
$ cd /tmp
$ cat a
apples
oranges
bananas
$ cat b
apples
mangoes
lemons
$ cat c
mangoes
limes
pears
$ cd ~
$ grep apples /tmp/* | grep mangoes
$
Nic nie znaleziono, ale plik b zawiera oba ciągi.
Oto, co myślę, że chce alwbtc
$ grep -l apples $(grep -l mangoes /tmp/*)
/tmp/b
-lopcję, aby oba polecenia były uważane za równe.
Rurociąg jeden grepdo drugiego:
grep "string1" /path/to/files/* | grep "string2"
Oto odpowiednik ackpolecenie do odpowiedzi RedGrittyBrick :
ack string2 $(ack string1 -l)
Działa w ten sam sposób (z wyjątkiem ackdomyślnie przeszukuje bieżący katalog rekurencyjnie). Treść w $()wyszukiwaniu, string1ale -lwyświetla tylko nazwy plików, w których znaleziono ten ciąg. Są one następnie przekazywane jako argumenty do polecenia zewnętrznego, co oznacza, że string2jest wyszukiwane tylko na tej liście plików.
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)
lub mniej zbędnie:
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/*)
Działa to, jeśli ciągi znaków znajdują się w różnych wierszach tego samego pliku, a także pozwala uniknąć fałszywych alarmów, jeśli nazwa pliku zawiera jeden z ciągów.
Aby rozwinąć rozwiązanie @ RedGrittyBrick, które ma wadę podczas uruchamiania polecenia nienadzorowanego plus, aby ukryć wyjście błędów zgodnie z przeznaczeniem i znaleźć rekurencyjnie pliki, które można rozważyć
grep -l 'STRING1' $(! grep -lrs 'STRING2' /absolute/path/to/search/dir && echo /dev/null)
-sopcja tłumi komunikaty o błędach
-ropcja pozwala na wyszukiwanie ciągów w dowolnie zagnieżdżonych katalogach w
!połączeniu z && echo /dev/nullgwarancją, że polecenie się nie rozłączy. W przeciwnym razie, jeśli inner grepnie znajdzie żadnego pliku, nie wypisze niczego, więc outer grepbędzie czekać w nieskończoność na wyszukiwanie. To rozwiązanie wyjścia /dev/nullw tych przypadkach tak outer grepbędzie szukać STRING1w /dev/nullktórym to miało nie znalezienie czegokolwiek.
Szukałem rozszerzalnego sposobu na wykonanie 2 lub więcej ciągów i wymyśliłem to:
grep -rl string1 path-to-files | xargs grep -l string2 | xargs grep -l string3
Pierwszy grep rekursywnie wyszukuje nazwy plików zawierających string1wewnątrz path-to-files.
Wyniki są przesyłane strumieniowo, do xargsktórego uruchamiane jest jedno lub więcej poleceń grep dla tych plików string2.
Wyniki są następnie przesyłane do innego xargspolecenia dla string3- jest to to samo, co pierwsze xargswywołanie, ale szuka innego ciągu.
Użycie opcji xargspozwoli uniknąć problemów w przypadku tak wielu wyników, że wynikowa linia poleceń wynikająca z użycia tyknięć zwrotnych jest zbyt długa.
Aby uniknąć ostrzeżeń, możemy przekierować stderrna /dev/null:
grep -rl string1 path-to-files 2>/dev/null | xargs grep -l string2
Nie jest potrzebny przy kolejnych wywołaniach grep, ponieważ string1został już znaleziony w pliku, więc uprawnienia są znane.
-lopcji zwracania nazw plików zamiast wierszy. Następnie używa znaku dolara lub cudzysłowu, aby przekazać tę listę jakoFILEargument do drugiego grepa. To pozwala drugiemu grepowi przeszukać cały każdy znaleziony plik zamiast poszczególnych linii, jak w moim rozwiązaniu.