Jak znaleźć pliki zawierające dwa ciągi razem w systemie Linux?

11

Chcę znaleźć pliki zawierające dwa ciągi razem, na przykład plik zawiera oba string1i string2.

Chcę pełną ścieżkę plików wyjściowych. Nie chcę widzieć ostrzeżeń „odmowa zgody”.

alwbtc
źródło

Odpowiedzi:

15
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
RedGrittyBrick
źródło
1
To fajne rozwiązanie i bardziej przydatne niż moje. Dla tych, którzy chcą wiedzieć, co się tutaj dzieje (zajęło mi to trochę czasu, aby to rozgryźć), korzysta z -lopcji zwracania nazw plików zamiast wierszy. Następnie używa znaku dolara lub cudzysłowu, aby przekazać tę listę jako FILEargument do drugiego grepa. To pozwala drugiemu grepowi przeszukać cały każdy znaleziony plik zamiast poszczególnych linii, jak w moim rozwiązaniu.
embedded.kyle
Pominięto -lopcję, aby oba polecenia były uważane za równe.
pong
2

Rurociąg jeden grepdo drugiego:

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

embedded.kyle
źródło
5
Jeśli dwa ciągi znajdują się w różnych wierszach pliku, to nie zadziała.
RedGrittyBrick
1
Nie wiedziałem, że musi być w tej samej linii @RedGrittyBrick
slhck
@slhck: Zaktualizowałem swoją odpowiedź, aby pokazać, co moim zdaniem alwbtc chce i dlaczego ta odpowiedź tego nie robi. Oczywiście mogłem źle zrozumieć, czego alwbtc chce i osadził. Kyle mógł mieć rację - podejrzewam, że nie.
RedGrittyBrick
1

Oto odpowiednik polecenie 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.

congusbongus
źródło
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)

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.

użytkownik381521
źródło
0

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.

pong
źródło
0

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.

awatts
źródło