Jak używać polecenia „grep” do znajdowania tekstu zawierającego podkatalogi

373

Chcę znaleźć wszystkie pliki, które zawierają określony ciąg tekstu. grepKomenda działa, ale nie wiem, jak go używać na każdym katalogu (mogę tylko zrobić dla mojego bieżącego katalogu). Próbowałem czytać man grep, ale nie pomogło.

Smile.Hunter
źródło
grep -RIn <yor pattern> * Wyszukuje z bieżących katalogów w dół we wszystkich plikach tekstowych. Nie wiem, jak mam wyszukiwać rekurencyjnie we wzorcach plików, takich jak * .C, używając tylko grep
1
--include="*.C"Symbol wieloznaczny z opcją @ user311346, dzięki @Lekensteyn.
Bob Stein
Użyj kombinacji find i grep, aby rekurencyjnie wyszukiwać pliki w celu znalezienia ciągu w bieżącym i we wszystkich podkatalogach. Sprawdź to wilddiary.com/find-files-containing-my-text
Drona

Odpowiedzi:

487

Lepiej byłoby użyć

grep -rl "string" /path

gdzie

  • -r--recursiveOpcja (lub ) służy do przeglądania również wszystkich podkatalogów /path, natomiast
  • -l--files-with-matchesOpcja (lub ) służy do drukowania tylko nazw plików pasujących plików, a nie pasujących linii (może to również poprawić szybkość, biorąc pod uwagę, że grepprzestanie czytać plik przy pierwszym dopasowaniu z tą opcją).
enzotib
źródło
13
Właściwie, jeśli „ciąg znaków” to wzór tekstowy do znalezienia, lepiej skorzystać z tej funkcji, w przeciwnym razie ktoś może napotkać problemy, gdy ciąg zawiera kropkę lub znak specjalny, który ma znaczenie w wyrażeniach regularnych, a nie tylko kropkę, którą należy znaleźć jako ciąg , jak jest. Następnie użyłbym -rlFprzełączników -Fdla „ustalonego ciągu” (a nie regexp - na przykład). Oczywiście, jeśli zadanie używało wyrażeń regularnych, to przepraszam. Jasne, ta sama teoria bez -r też często widzę, że ludzie zakładają, że grep wyszukuje „tekst” i może powodować problemy, które specjalne, które oznaczają coś jako wyrażenie regularne.
LGB,
4
Jest też -iflaga, która ignoruje wielkość liter.
Marco Ceppi
3
Chciałbym tylko pokazać --recursiveopcję, jest mnóstwo opcji i scenariuszy użytkowania, o których można mówić. Zacząłem od @dmityugov zaakceptował odpowiedź i zmodyfikowałem do pracy bez find.
enzotib
1
@NN: zrobione :-)
enzotib
3
@ScottBiggs: z opcją--include '*.h'
enzotib
167

Jeśli szukasz linii pasujących do plików, moim ulubionym poleceniem jest:

grep -Hrn 'search term' path/to/files
  • -H powoduje wydrukowanie nazwy pliku (domyślnie przy wyszukiwaniu wielu plików)
  • -r wykonuje wyszukiwanie rekurencyjne
  • -n powoduje wydrukowanie numeru linii

path/to/filesmoże być .wyszukiwanie w bieżącym katalogu

Inne opcje, które uważam za bardzo przydatne:

  • -Iignoruj ​​pliki binarne (uzupełnienie: -atraktuj wszystkie pliki jak tekst)
  • -Ftraktuj search termjako wyrażenie dosłowne, a nie regularne
  • -i wykonaj wyszukiwanie bez rozróżniania wielkości liter
  • --color=alwaysaby wymusić kolory nawet podczas przepuszczania less. Aby utworzyć lesskolory pomocnicze, musisz użyć -ropcji:

    grep -Hrn search . | less -r
    
  • --exclude-dir=dirprzydatne do wykluczania katalogów takich jak .svni .git.

Przykładowe dane wyjściowe

Lekensteyn
źródło
13
-Hfolder jest redundantny, jeśli istnieje więcej niż jeden plik, co jest prawdopodobne. W rzeczywistości strona -H, --with-filename: Print the file name for each match. This is the default when there is more than one file to search.
podręcznika
Nie wiedziałem o tym, zawsze działało tak, jak się spodziewałem. To moje domyślne polecenie podczas wyszukiwania plików.
Lekensteyn,
1
Czy istnieje sposób, aby rozważyć tylko pliki z, powiedzmy, rozszerzeniem .a (i połączyć to z -r)?
user2413,
6
@ user2413 Try--include '*.*'
Lekensteyn
1
@alper Trygrep --exclude='*~' ...
Lekensteyn
24

Wierzę, że możesz użyć czegoś takiego:

find /path -type f -exec grep -l "string" {} \;

Wyjaśnienie na podstawie komentarzy

findto polecenie, które pozwala znaleźć pliki i inne obiekty, takie jak katalogi i łącza w podkatalogach danej ścieżki. Jeśli nie określisz maski, którą nazwy plików powinny spełniać, wyliczy wszystkie obiekty katalogu.

  • -type f określa, że ​​powinien przetwarzać tylko pliki, a nie katalogi itp.
  • -exec grepokreśla, że ​​dla każdego znalezionego pliku należy uruchomić polecenie grep, przekazując mu nazwę pliku jako argument, zastępując {}go nazwą pliku
dmityugov
źródło
3
Tylko dla tych, którzy nie wiedzą, dodanie -name '*.py'ogranicza dopasowania do plików z rozszerzeniem „.py”.
Daniel F
Podoba mi się, że dotyczy to klientów, którzy nie mają zaimplementowanej opcji -R w poleceniu grep.
Aviose
Jeśli chcesz wydrukować pasującą linię ORAZ nazwę pliku, wykonaj exec w następujący sposób:... -exec bash -c 'grep -r "mystring" {} && echo {}' \;
Donn Lee
jaki jest względny stosunek do bezpośredniego użycia grep?
jonathan
19

Moje domyślne polecenie to

grep -Rin string *

Używam kapitolu „R”, ponieważ lsużywa go do rekurencji. Ponieważ grep akceptuje oba, nie ma powodu, aby go nie używać.

EDYCJA: na HVNSweeting, najwyraźniej -Rbędzie podążać za dowiązaniami symbolicznymi, gdzie -rnie będzie.

użytkownik606723
źródło
1
Aby wyszukiwać również w ukrytych plikach, uruchom shopt -s dotglob(pamiętaj -sjako „ustaw”). Zachowaj ostrożność podczas usuwania plików. Jeśli masz włączoną funkcję dotglob, rm -r *usuwa wszystko w bieżącym katalogu , ale także katalog nad nim, ponieważ ..pasuje. Aby wyłączyć dotglob, użyj shopt -u dotglob(„unset”). Zmiany są jednak tymczasowe, dotyczą tylko bieżącej powłoki.
Lekensteyn,
Zapomniałem o tym. Czy istnieje sposób, aby ustawić to dla jednej linii? coś jak shopt -s dotglob & <grep cmd> & shopt -y dotglobtylko wygodniejszego? W ten sposób nie będziemy musieli się martwić o jego zresetowanie
użytkownik606723,
Ponadto prawdopodobnie jest łatwiejszy w użyciu grep -Rin string .w większości tych przypadków. Po prostu używam *, ponieważ wydaje się, że jest to bardziej naturalne.
user606723,
1
jeśli wykonasz rekurencyjne grep, możesz po prostu zacząć od „.” zamiast "*". nie wymaga dotglob.
Michał Šrajer,
1
głosujcie na to, jedna rzecz nie wspomina na stronie podręcznika, że Rbędzie podążać za dowiązaniami symbolicznymi, ra nie
HVNSweeting 25.01.2013
12

Jeśli chcesz spróbować czegoś nowego, spróbuj ack. Polecenie rekurencyjnego przeszukiwania bieżącego katalogu stringto:

ack string

Instalacja jest dość prosta:

curl http://betterthangrep.com/ack-standalone > ~/bin/ack && chmod 0755 !#:3

(Pod warunkiem, że masz już katalog, ~/bina najlepiej w twoim PATH.)

Konrad Rudolph
źródło
2
Lub po prostu apt-get zainstaluj ack-grep (i dodaj alias ack = ack-grep do swojego .bashrc)
markijbema
Co robią ostatnie parametry chmodpolecenia? Czy są one specyficzne chmodlub związane z bash ( !#:3część)?
Elliott Darfink
@ElliottDarfink Korzysta z funkcji historii Basha - !jest oznaczeniem wydarzenia . Są dość potężne, aby uniknąć powtórzeń. !#:3odwołuje się do trzeciego tokena wiersza poleceń, tj. ~/bin/ackw tym przypadku.
Konrad Rudolph
4

Polecenie rgrep jest dedykowane do takiej potrzeby

Jeśli nie jest dostępny, możesz to zrobić w ten sposób

mkdir -p ~/bin
cd ~/bin
wget http://sdjf.esmartdesign.com/files/rgrep
chmod +x rgrep

Możesz bezpośrednio ustawić domyślne opcje grep, jak opisano powyżej.

Osobiście używam

[[  ${#args} -lt 5 && "${args//[[:space:]]/}" == "-i" ]] && args="-Hin"
args="${args:--Hns} --color=auto"

powiązany temat: jak zawsze używać rgrep z kolorem

mnono
źródło
rgrep jest dostarczany przez pakiet grep, który jest domyślnie instalowany w Ubuntu.
karel
2

Aktualizacja 2:

Ta linia poleceń używa findi greprozwiązuje problem:

$ find path_to_search_in -type f -exec grep -in searchString {} 2> /dev/null +

--color=<always or auto> dla kolorowych wydruków:

$ find path_to_search_in -type f \
            -exec grep --color=always -in searchString {} 2>/dev/null +

Przykład:

$ find /tmp/test/ -type f -exec grep --color=auto -in "Search string" {} 2>/dev/null +

Przykład uruchom na poniższej migawce: Snap1


Aktualizacja 1:

Możesz wypróbować następujący kod; jako funkcję w swojej .bashrcOr .bash_aliaseslub w skrypcie:

wherein () 
{ 
    for i in $(find "$1" -type f 2> /dev/null);
    do
        if grep --color=auto -i "$2" "$i" 2> /dev/null; then
            echo -e "\033[0;32mFound in: $i \033[0m\n";
        fi;
    done
}

Stosowanie: wherein /path/to/search/in/ searchkeyword

przykład:

$ wherein ~/Documents/ "hello world"

(Uwaga: zgodnie z sugestią @enzotib w komentarzach poniżej, nie działa to z plikami / katalogami zawierającymi spacje w ich nazwach).


Oryginalny post

Aby wyszukać ciąg i wyprowadzić tylko ten wiersz z ciągiem wyszukiwania:

$ for i in $(find /path/of/target/directory -type f); do \
    grep -i "the string to look for" "$i"; done

na przykład:

$ for i in $(find /usr/share/applications -type f); \
    do grep -i "web browser" "$i"; done

Aby wyświetlić nazwę pliku zawierającą szukany ciąg:

$ for i in $(find /path/of/target/directory -type f); do \
    if grep -i "the string to look for" "$i" > /dev/null; then echo "$i"; fi; done;

na przykład:

$ for i in $(find /usr/share/applications -type f); \
    do if grep -i "web browser" "$i" > /dev/null; then echo "$i"; \
    fi; done;
precyzyjny
źródło
Nie działa w nazwach plików zawierających spacje. Niepowodzenie jest ukrywane przez fakt, że stderr nie jest pokazywany.
enzotib
@enzotib dziękuję za zwrócenie na to uwagi .. wciąż nie jest rozwiązane dla określonej funkcji .. Dodałem jednak jeszcze jedną linijkę ..
dokładnie
Teraz odpowiedź jest podobna do odpowiedzi @dmityugov.
enzotib
tak, ale w tym sensie większość odpowiedzi na tej stronie, jeśli zaznaczysz, jest podobnych pod względem używanych grep, oprócz tego, że jest to podzbiór używający findz grep... ale jeśli chcesz zaakceptować różne przełączniki i poprawki jako odrębną odpowiedź, prawdopodobnie mój też tu będzie pasował ... a może się różnisz? ostatnia aktualizacja działa tak, jak chciałbym podczas wyszukiwania: nazwy plików z wierszami z kluczem wyszukiwania i wiersz nr. też :) oraz kolorowy filtr wyjściowy i filtr błędów dla lepszej czytelności.
precyzyjnie
2

grep( GNU lub BSD )

Możesz użyć grepnarzędzia do rekurencyjnego przeszukiwania bieżącego folderu za pomocą -rparametru, takiego jak:

grep -r "pattern" .

Uwaga: -r- Rekurencyjnie przeszukuj podkatalogi.

Aby wyszukiwać w określonych plikach, możesz użyć składni globowania, takiej jak:

grep "class foo" **/*.c

Uwaga: Korzystając z opcji globbing ( **), skanuje rekursywnie wszystkie pliki z określonym rozszerzeniem lub wzorem. Aby włączyć tę składnię, uruchom: shopt -s globstar. Możesz również użyć **/*.*do wszystkich plików (z wyjątkiem ukrytych i bez rozszerzenia) lub dowolnego innego wzoru.

Jeśli masz błąd, że Twój argument jest za długi, rozważ zawężenie wyszukiwania lub użyj findskładni, na przykład:

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, takich jak:

rg "pattern" .

Zapoznaj się z dokumentacją, krokami instalacji lub kodem źródłowym na stronie projektu GitHub .

To znacznie szybciej niż jakiekolwiek inne narzędzia jak GNU / BSD grep , ucg, ag, sift, ack, ptlub podobny, ponieważ jest zbudowany na silniku regex Rust , który używa automatów skończonych, SIMD i agresywny dosłownych optymalizacje aby szukają bardzo szybko.

Obsługuje wzorce ignorowania określone w .gitignoreplikach, więc pojedynczą ścieżkę pliku można dopasować do wielu wzorców globu 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(np. -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 linii. Można łączyć z -H.
kenorb
źródło
1

Robię to za pomocą xargs, bardzo niedocenianego polecenia

find ./ -type f -print0 | xargs -0 grep 'string_you_are_looking_for'

find ./ daje ci rekurencyjną listę wszystkich plików w bieżącym folderze, a następnie potokujesz ją do xargs, który wykonuje polecenie grep na każdym z tych plików

martwy programista
źródło
4
Użycie xargsbez -print0opcji do findi -0opcja xargsjest przestarzałe, nie powiedzie się w nazwach plików zawierających spacje.
enzotib
@enzotib Zredagowałem odpowiedź zgodnie z sugestią. - proszę przejrzeć, a jeśli zajdzie potrzeba edycji i poprawiania, chętnie dokonam ponownej edycji. dziękuję
αғsнιη
1
@KasiyA: teraz jest w porządku, usunąłem moją opinię.
enzotib
0

Wiem, że jest tu wiele odpowiedzi, ale oto alternatywa, jeśli chcesz dodać inne ograniczenia podczas wyszukiwania plików:

find . -type f -exec grep --quiet string_to_look_for {} ';' -print

Działa to, ponieważ grepzwróci 0, jeśli znajdzie wynik, 1 w przeciwnym razie. Na przykład możesz znaleźć pliki o wielkości 1 MB i zawierające coś:

find . -type f -exec grep --quiet string_to_look_for {} ';' -size 1M -print

W przypadku wielu wymagań prawdopodobnie będziesz chciał użyć flagi optymalizatora, -Októra istnieje w GNU grep.

Ztyx
źródło
0

Skrypt (find-in-code) do wyszukiwania w kodzie C, CPP:

#!/bin/sh

find . \( -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" \) -type f -print0 | xargs -0 grep --color -n "$1"

Posługiwać się:

find-in-code "search string"
nvd
źródło