Pytanie Jak znaleźć wszystkie pliki zawierające określony tekst w systemie Linux?


Próbuję znaleźć sposób na zeskanowanie całego systemu Linux dla wszystkich plików zawierających określony ciąg tekstu. Aby wyjaśnić, szukam tekstu w pliku, a nie w nazwie pliku.

Kiedy sprawdzałem, jak to zrobić, dwukrotnie natknąłem się na to rozwiązanie:

find / -type f -exec grep -H 'text-to-find-here' {} \;

Jednak to nie działa. Wydaje się wyświetlać każdy pojedynczy plik w systemie.

Czy jest to właściwe, aby to zrobić? Jeśli nie, w jaki sposób powinienem? Ta umiejętność znajdowania ciągów tekstowych w plikach byłaby niezwykle przydatna w niektórych projektach programistycznych, które robię.


3693
2018-06-06 08:06


pochodzenie


pamiętaj, że grep zinterpretuje każdy . jako wieloznaczny pojedynczy znak, między innymi. Moja rada to zawsze używać fgrep lub egrep. - Walter Tross
zresztą prawie tam byłeś! Wystarczy wymienić -H z -l (I może grep z fgrep). Aby wykluczyć pliki o określonych wzorach nazw, których używałbyś findw bardziej zaawansowany sposób. Warto się tego nauczyć find, chociaż. Właśnie man find. - Walter Tross
find … -exec <cmd> + jest łatwiejszy do wpisania i szybszy niż find … -exec <cmd> \;. Działa tylko wtedy, gdy <cmd> akceptuje dowolną liczbę argumentów nazw plików. Oszczędność czasu wykonania jest szczególnie duża, jeśli <cmd> jest powolny, aby uruchamiać się jak skrypty w języku Python lub Ruby. - hagello
Aby wyszukać nierekurencyjnie w podanej ścieżce, polecenie to `grep --include = *. Txt -snw" wzorzec "thepath / *. - Stéphane Laurent
@ StéphaneLaurent Myślę, że zbytnio to komplikujesz. Tylko powiedz grep "pattern" path/*.txt - fedorqui


Odpowiedzi:


Wykonaj następujące czynności:

grep -rnw '/path/to/somewhere/' -e 'pattern'
  • -r lub -R jest rekurencyjny,
  • -n jest numerem linii, i
  • -w oznacza pasujące do całego słowa.
  • -l (małe litery L) można dodać, aby podać nazwę pliku pasujących plików.

Wraz z tymi, --exclude, --include, --exclude-dir flagi mogą być użyte do wydajnego wyszukiwania:

  • Przeszuka tylko te pliki, które mają rozszerzenia .c lub .h:

    grep --include=\*.{c,h} -rnw '/path/to/somewhere/' -e "pattern"
    
  • Wyklucza to wyszukiwanie wszystkich plików kończących się rozszerzeniem .o:

    grep --exclude=*.o -rnw '/path/to/somewhere/' -e "pattern"
    
  • W przypadku katalogów można wykluczyć określone katalogi --exclude-dir parametr. Na przykład, to wykluczy katalog dir dir1 /, dir2 / i wszystkie z nich pasujące do * .dst /:

    grep --exclude-dir={dir1,dir2,*.dst} -rnw '/path/to/somewhere/' -e "pattern"
    

Działa to bardzo dobrze dla mnie, aby osiągnąć prawie taki sam cel jak twój.

Aby uzyskać więcej opcji, sprawdź man grep.


6681
2018-06-06 08:21



użyj --exclude. jak "grep -rnw --exclude = *. o 'katalog" -e "wzór" - rakib_
Uważam, że parametr grep --include jest bardzo użyteczny. Na przykład: grep -rnw --include = *. Java. -e "czegokolwiek szukam" - Lucas A.
warto zauważyć: wydaje się, że r opcja jest leniwy (przemierza głebokość-pierwszy, niż zatrzymuje się po pierwszym katalogu), natomiast R jest chciwy (poprawnie przemieści całe drzewo). - Eliran Malka
Uwaga (szczególnie dla początkujących): Znaczniki cudzysłowu w powyższym poleceniu są ważne. - madD7
@ Eliran Malka R en r będzie poprawnie przeglądać katalogi, ale R będzie śledzić dowiązania symboliczne. - bzeaman


Możesz użyć grep -ilR:

grep -Ril "text-to-find-here" /
  • i oznacza przypadek ignorowania (opcjonalnie w twoim przypadku).
  • R oznacza rekursywne.
  • l oznacza "pokaż nazwę pliku, a nie sam wynik".
  • / oznacza rozpoczęcie od źródła twojej maszyny.

1087
2018-06-06 08:08



Na podstawie mojego doświadczenia, -i spowalnia, więc nie używaj go, jeśli nie jest to konieczne. Przetestuj go w pewnym katalogu, a następnie uogólnij. Powinien zostać ukończony w ciągu kilku minut. Myślę, że regularne wyrażenie spowolniłoby to. Ale moje komentarze opierają się na przypuszczeniach, sugeruję, żebyś to przetestował time przed linią. - fedorqui
Tak, /* oznacza to. W każdym razie właśnie przetestowałem to i zauważyłem, że właśnie / Prace. - fedorqui
Jeśli nie korzystasz z wyrażeń regularnych, możesz użyć polecenia fgrep zamiast grep na większości systemów. - markle976
Tak @ markle976, w rzeczywistości z man grep: fgrep is the same as grep -F -> Interpret PATTERN as a list of fixed strings. - fedorqui
Możesz zamienić ścieżkę do katalogu / grep -Ril "text-to-find-here" ~/sites/ albo użyj . dla bieżącego katalogu grep -Ril "text-to-find-here" . - Black


Możesz użyć ack. To jest jak grep dla kodu źródłowego. Możesz skanować cały system plików za jego pomocą.

Po prostu zrób:

ack 'text-to-find-here'

W twoim katalogu głównym.

Możesz także użyć wyrażenia regularne, podaj typ pliku itp.


AKTUALIZACJA

Właśnie odkryłem Srebrny poszukiwacz, który jest podobny do potwierdzenia, ale 3-5 razy szybszy od niego i nawet ignoruje wzorce z a .gitignore plik.


234
2018-06-06 08:26



Bardzo przydatny, prosty i szybki. Ostrzeżenie: "W dystrybucji wywodzącej się z dystrybucji Debian, ack jest pakowany jako" ack-grep ", ponieważ" ack "już istniało" (z beyondgrep.com/install). Możesz na koniec uruchomić konwerter kodu Kanji na tych systemach Linux ... - Jose_GD
ack lub ack-grep ma ładne podkreśla, ale znaleźć + grep, gdy właściwe używane jest znacznie lepiej w wydajności - Sławomir Lenart
Zauważ, że ripgrep jest szybszy niż cokolwiek, o czym tutaj mowa, w tym The Silver Searcher i zwykły "grep gre". Widzieć ten wpis na blogu na dowód. - Radon Rosborough


Możesz użyć:

grep -r "string to be searched"  /path/to/dir

The r oznacza rekursywne, a więc wyszuka określoną ścieżkę, a także jej podkatalogi. To powie ci nazwę pliku, a także wydrukuje wiersz w pliku, w którym pojawi się ciąg znaków.

Lub polecenie podobne do tego, które próbujesz (przykład:) do wyszukiwania we wszystkich plikach javascript (* .js):

find . -name '*.js' -exec grep -i 'string to search for' {} \; -print

Spowoduje to wydrukowanie linii w plikach, w których pojawia się tekst, ale nie drukuje nazwy pliku.

Oprócz tego polecenia możemy to również napisać: grep -rn "Łańcuch do wyszukania" / ścieżka / do / katalog / lub / plik -r: wyszukiwanie cykliczne n: numer linii zostanie wyświetlony dla dopasowań


126
2018-03-14 23:29



Thanx dla wersji find. Moja wersja grep (busybox dla NAS) nie ma opcji -r, naprawdę potrzebowałem innego rozwiązania! - j.c
Dziękujemy za wersję "znajdź"! Bardzo ważne jest, aby móc filtrować według ".js "lub".txt ', itp. Nikt nie chce spędzać godzin czekając na grep, aby zakończyć wyszukiwanie wszystkich wielobajtowych filmów z ostatnich wakacji rodzinnych, nawet jeśli polecenie jest łatwiejsze do wpisania. - mightypile


Możesz użyć tego:

grep -inr "Text" folder/to/be/searched/

83
2017-07-31 13:44



najłatwiejszy, pełny, rekurencyjny i niewrażliwy na wielkość liter. kciuki w górę. - Francesco Casula
jeśli dodasz -A3 jest jeszcze lepszy - albanx
To bardzo fajnie. - kodmanyagha


Lista nazw plików zawierających dany tekst

Przede wszystkim uważam, że skorzystałeś -H zamiast -l. Możesz także spróbować dodać tekst w cudzysłowie, po którym następuje {} \.

find / -type f -exec grep -l "text-to-find-here" {} \; 

Przykład

Załóżmy, że szukasz plików zawierających określony tekst "Licencja Apache" w twoim katalogu. Wyświetli wyniki nieco podobne do poniższych (dane wyjściowe będą różne w zależności od zawartości katalogu).

bash-4.1$ find . -type f -exec grep -l "Apache License" {} \; 
./net/java/jvnet-parent/5/jvnet-parent-5.pom
./commons-cli/commons-cli/1.3.1/commons-cli-1.3.1.pom
./io/swagger/swagger-project/1.5.10/swagger-project-1.5.10.pom
./io/netty/netty-transport/4.1.7.Final/netty-transport-4.1.7.Final.pom
./commons-codec/commons-codec/1.9/commons-codec-1.9.pom
./commons-io/commons-io/2.4/commons-io-2.4.pom
bash-4.1$ 

Usuń wielkość liter

Nawet jeśli nie używasz w tym przypadku jak "tekst" kontra "TEKST", możesz użyć skrótu -i przełącz na ignorowanie przypadku. Możesz przeczytać dalsze szczegóły tutaj.

Mam nadzieję, że to ci pomoże.


50
2017-11-09 13:18



OP poprosił o pliki zawierające tekst w ich treści, a nie nazwę pliku. - Auxiliary
Oto, co robi to polecenie: find przekaże wszystkie znalezione ścieżki do polecenia grep -l "text-to-find-here" <file found>". Możesz dodać ograniczenia do nazwy pliku, np. find / -iname "*.txt" wyszukiwać tylko w plikach, których nazwa kończy się na .txt - Mene
@Aplik pomocniczy - zawiera przykładowe wyjście, aby uniknąć nieporozumień dla czytelników. - lkamal
@Mene To naprawdę smutny stan, w którym komentarz Pomocy ma więcej głosów niż twoja ... nawet jeśli ich komentarz pochodzi z 2014 roku, a twój jest 2017, to ich komentarz ma 6, kiedy powinien mieć dokładnie 0, a twój miał tylko jeden (teraz dwa). W czymś, w co chciałbym wierzyć. - Pryftan
@Mene To powiedziawszy -iname nie rozróżnia wielkości liter, co oznacza, że ​​znalazłoby również pliki .TXT, na przykład, TxT i TXt i tak dalej. - Pryftan


Jeżeli twój grep nie obsługuje wyszukiwania cyklicznego, można łączyć find z xargs:

find / -type f | xargs grep 'text-to-find-here'

Uważam, że jest to łatwiejsze do zapamiętania niż format find -exec.

Spowoduje to wyprowadzenie nazwy pliku i zawartości dopasowanej linii, np.

/home/rob/file:text-to-find-here

Opcjonalne flagi, do których możesz dodać grep:

  • -i - wyszukiwanie bez rozróżniania wielkości liter
  • -l - wypisuje tylko nazwę pliku, w którym znaleziono dopasowanie
  • -h - wypisuje tylko linię, która się zgadza (nie nazwa pliku)

47
2018-06-20 08:49



Jest to równoważne grep 'text-to-find-here' bez nazwy pliku, jeśli find niczego nie znajduje. Spowoduje to zawieszenie się i oczekiwanie na dane wprowadzone przez użytkownika! Dodaj --no-run-if-empty jako opcja do xargs. - hagello
Ta kombinacja find i xargs nie działa zgodnie z zamierzeniami, jeśli nazwy plików lub katalogów zawierają spacje (znaki, które xargs interpretuje jako separatory). Posługiwać się find … -exec grep … +. Jeśli nalegasz na użyciu find razem z xargs, użyj -print0 i -0. - hagello


grep -insr "pattern" *
  • i: Ignoruj ​​rozróżnianie wielkości liter w pliku PATTERN i plikach wejściowych.
  • n: Prefix każdej linii wyjściowej z numerem wiersza opartym na 1 w jego pliku wejściowym.
  • s: Zablokuj komunikaty o błędach dotyczące nieistniejących lub nieczytelnych plików.
  • r: Czytaj wszystkie pliki w każdym katalogu, rekurencyjnie.

34
2018-02-26 05:47



Czy możesz wyjaśnić, w jaki sposób twoja odpowiedź poprawia się na inne odpowiedzi lub w jaki sposób jest wystarczająco odmienny od nich? - Amos M. Carpenter
niezbyt skomplikowane do zapamiętania, obejmie wszystkie wzorce (case-senstivity -> off, zawiera nazwy plików i numer linii i wykona rekursywne wyszukiwanie itp.) i użycie "*" na końcu przeszuka wszystkie katalogi (bez potrzeby określania żadnych ścieżka lub nazwa katalogu). - enfinet
Przepraszam, powinienem był być bardziej klarowny: byłoby wspaniale, gdybyś mógł uwzględnić to wyjaśnienie w swojej odpowiedzi. W obecnej formie, szczególnie przy tak wielu innych podobnych już odpowiedziach, trudno jest dostrzec z tak krótkiej odpowiedzi, jaką korzyść stanowi próbowanie to nad zaakceptowaną odpowiedzią lub jedną z przegłosowanych. - Amos M. Carpenter
To jest dobra odpowiedź + dobre wyjaśnienie - khelili miliana
@ AmosM.Carpenter Jedna rzecz, którą uwielbiam w tej odpowiedzi, wskazuje na argument tłumienia, który może pomóc odfiltrować hałas, który nie ma znaczenia przy uzyskiwaniu pożądanych rezultatów. Grep drukuje błędy typu: "Funkcja nie zaimplementowana", "Nieprawidłowy argument", "Zasób niedostępny" itp. W niektórych "plikach". - leetNightshade


grep (GNU ANTYLOPA lub BSD)

Możesz użyć grep narzędzie do wyszukiwania rekurencyjnie bieżącego folderu, takie jak:

grep -r "class foo" .

Uwaga: -r - Rekurencyjne przeszukiwanie podkatalogów.

Możesz również użyć składni globowania do wyszukiwania w określonych plikach, takich jak:

grep "class foo" **/*.c

Uwaga: Za pomocą opcja globowania (**), skanuje wszystkie pliki rekurencyjnie z określonym rozszerzeniem lub wzorcem. Aby włączyć tę składnię, uruchom: shopt -s globstar. Możesz również użyć **/*.* dla wszystkich plików (z wyłączeniem ukrytego i bez rozszerzenia) lub dowolnego innego wzorca.

Jeśli masz błąd, że argument jest za długi, zastanów się nad zawężeniem wyszukiwania lub użyciem find zamiast tego składnia taka jak:

find . -name "*.php" -execdir grep -nH --color=auto foo {} ';'

Alternatywnie użyj ripgrep.

ripgrep

Jeśli pracujesz nad większymi projektami lub dużymi plikami, powinieneś użyć ripgrep zamiast tego, jak:

rg "class foo" .

Zamów dokumenty, kroki instalacji lub kod źródłowy na Strona projektu GitHub.

Jest o wiele szybszy niż jakiekolwiek inne narzędzie, takie jak GNU ANTYLOPA/BSD  grep, ucg, ag, sift, ack, pt lub podobnie, ponieważ jest zbudowany na Rdzeniowy silnik regex która używa automatów skończonych, SIMD i agresywnych dosłownych optymalizacji, aby wyszukiwanie było bardzo szybkie.

Obsługuje wzorce ignorowania określone w .gitignore plików, dzięki czemu pojedyncza ścieżka do pliku może być dopasowana do wielu wzorców globalnych jednocześnie.


Możesz użyć wspólnych parametrów, takich jak:

  • -i - Niewrażliwe wyszukiwanie.
  • -I - Zignoruj ​​pliki binarne.
  • -w - Wyszukaj całe słowa (w przeciwieństwie do częściowego dopasowywania słów).
  • -n - Pokaż linię swojego meczu.
  • -C/--context (na przykład. -C5) - Zwiększa kontekst, dzięki czemu widzisz otaczający kod.
  • --color=auto - Zaznacz pasujący tekst.
  • -H - Wyświetla nazwę pliku, w którym znajduje się tekst.
  • -c - Wyświetla liczbę pasujących wierszy. Można łączyć z -H.

29
2018-05-09 10:11



Uważam też, że rozszerzony globbing jest użyteczny. Należy jednak pamiętać, że w przypadku naprawdę dużej liczby plików można uzyskać komunikat "Zbyt długi argument za długi argumentu". (Prosty globbing jest również podatny na tego typu błędy). - Yoory N.