Czy istnieje prostszy sposób na grepowanie wszystkich plików w katalogu?

21

Kiedy chcę przeszukać całe drzewo w poszukiwaniu jakiejś zawartości, używam

find . -type f -print0 | xargs -0 grep <search_string>

Czy istnieje lepszy sposób na zrobienie tego pod względem wydajności lub zwięzłości?

Dancrumb
źródło
2
@Downvoter: Z przyjemnością poprawię to pytanie, jeśli możesz podzielić się swoimi obawami.
Dancrumb,
2
wiele wersji find ma wbudowane xargs: find. -type f -exec fgrep <ciąg_wyszukiwania> {} +
simpleuser

Odpowiedzi:

42

Sprawdź, czy opcja grepwsparcia -r(w przypadku ponownego wystąpienia ):

grep -r <search_string> .
Philippos
źródło
1
Tak ... Właśnie znalazłem stackoverflow.com/questions/16956810/... i tam też jest odpowiedź.
Dancrumb,
dodaj komentarz dotyczący --exclude-dirwydajności, a my mamy zwycięzcę!
Dancrumb,
1
Zauważ, że nie jest to przenośne, jednak grepw najnowszych dystrybucjach FreeBSD i Linux go obsługuje. A dlaczego --exclude-dir? Nie prosiłeś o przeszukanie całego drzewa ?
Philippos
Słuszny punkt ... --exclude-dirjest w rzeczywistości przydatny w moim przypadku użycia (ponieważ części poddrzewa są duże, ale bezużyteczne) i zapytałem o wydajność ... ale masz rację, nie jest to konieczne.
Dancrumb,
W tym przypadku muszę dodać, że IIRC --exclude-dirjest wyłączne dla GNU grep. (-:
Philippos
13

Nieoptymalna odpowiedź: Zamiast przesyłać dane wyjściowe finddo grep, możesz po prostu uruchomić

find . -type f -exec grep 'research' {} '+'

i voila, jedno polecenie zamiast dwóch!

wyjaśnienie:

find . -type f

znajdź wszystkie zwykłe pliki.

-exec grep 'research'

grep „research”

{}

w znalezionej nazwie pliku

'+'

użyj jednego polecenia dla wszystkich nazw plików, a nie raz dla nazwy pliku.

Uwaga: z ';'tym byłby raz na nazwę pliku.

Poza tym, jeśli używasz go do przetwarzania kodu źródłowego, możesz zajrzeć do niego ack, co jest przeznaczone do łatwego wyszukiwania bitów kodu.

ack

Edytować :

Możesz trochę rozszerzyć te badania. Po pierwsze, możesz użyć -name ''przełącznika, findaby wyszukać pliki z określonym wzorcem nazewnictwa.

Na przykład :

  • tylko pliki odpowiadające dziennikom: -name '*.log'

  • tylko pliki odpowiadające nagłówkom c, ale nie możesz trzymać się wielkich lub małych liter dla rozszerzeń plików: -iname *.c

Nb: jak dla grepi ack, -iprzełącznik oznacza w tym przypadku rozróżnianie wielkości liter.

W takim przypadku grep wyświetli się bez koloru i bez numerów linii.

Można to zmienić z --colori -nprzełączniki (numery kolorów i linii w plikach odpowiednio).

Na koniec możesz mieć coś takiego:

find . -name '*.log' -type f -exec grep --color -n 'pattern' {} '+'

na przykład

$ find . -name '*.c' -type f -exec grep -n 'hello' {} '+' 
./test2/target.c:1:hello
Pierre-Antoine Guillaume
źródło
5
ackjest świetny, a szybsza wersja ackto ag(srebrny wyszukiwarka, geoff.greer.fm/ag )
cfeduke
1
Wolę to z filtrem jak -name '*.log'To jest szybsze.
sdkks,
@ cfeduke Nie próbowałem tego, głównie dlatego, że ag nie jest częścią domyślnych repozytoriów apt na WSL (musisz pracować z tym, co masz!)
Pierre-Antoine Guillaume
Sztuką jest dodanie / dev / null do grep, aby pojawiła się nazwa pliku.
ChuckCottrill
Sztuką jest wyszukiwanie tylko katalogów, a następnie -exec grep / dev / null {} / *, aby uzyskać wszystkie pliki z jednym rozwidleniem / exec na katalog.
ChuckCottrill
12

Jeśli chcesz przekierować do podkatalogów:

grep -R 'pattern' .

Ta -Ropcja nie jest opcją standardową, ale jest obsługiwana przez większość popularnych grepimplementacji.

Kusalananda
źródło
7
Użyj -rzamiast -Rpomijać dowiązania symboliczne, gdy dotyczy GNU grep
αғsнιη
1
@AFSHIN Dlaczego nie chcesz śledzić dowiązań symbolicznych?
Kusalananda
4
@Kusalananda Recursion? Chociaż obecne grepimplementacje GNU wychwytują rekurencje, myślę. W przeciwnym razie zależy to od tego, co rozumiesz przez „drzewo”.
Philippos
2
@Filippos IMHO, opieka nad użytkownikiem nie jest czymś, co greppowinno zrobić narzędzie . Jeśli użytkownik ma symboliczne pętle linków w swojej strukturze katalogów, to jest problem użytkownika :-)
Kusalananda
3
@Kusalananda A jeśli system zapewnił pętlę? Nigdy się nie zagubiłem /sys/devices/cpu/subsystem/devices/cpu/subsystem/devices/cpu/...(-XI jak narzędzia opiekujące się mną (chyba że zapewniają dziwną magię, nazywają „AI”). (-;
Philippos
5

Jak wspomniano powyżej -rlub -R(w zależności od pożądanej obsługi dowiązań symbolicznych) jest szybką opcją.

-d <action>Czasami jednak może się przydać.

Przyjemną rzeczą -djest komenda skip, która ucisza „grep: nazwa_katalogu: Jest katalogiem”, gdy chcesz tylko przeskanować bieżący poziom.

$ grep foo * 
grep: q2: Is a directory 
grep: rt: Is a directory 

$ grep -d skip foo *  
$ 

i oczywiście:

$ grep -d recurse foo * 
(list of results that don't exist because the word foo isn't in our source code
and I wouldn't publish it anyway).  
$ 

-d skipOpcja jest naprawdę przydatne wewnątrz innego skryptu, dzięki czemu nie trzeba 2> /dev/null. :)

Petro
źródło
0

Jeśli masz do czynienia z wieloma plikami, grep działa szybciej, jeśli przycinasz pliki, które musi przeszukać, zamiast grepowania wszystkich plików w podfolderach.

Czasami używam tego formatu:

grep "primary" `find . | grep cpp$`

Znajdź wszystkie pliki w podfolderach .tego końca w cpp. Następnie grep te pliki dla „podstawowego”.

Jeśli chcesz, możesz przesyłać dalej te wyniki do kolejnych wywołań grep:

grep "primary" `find . | grep cpp$` | grep -v "ignoreThis" | grep -i "caseInsensitiveGrep"
Rudy
źródło
1
backtics nie są dobrą nowoczesną praktyką, wszystkie są już przestarzałe
Christopher
1
To się zepsuje, jeśli masz pliki ze znakami specjalnymi w ich nazwach. Nie wiem, jak wyjątkowe muszą być, aby były zbyt wyjątkowe, aby działało tak, jak jest, ale to, co robisz, jest w rzeczywistości tym samym, co analizowanie wyniku ls, co również jest złe.
CVn