Jak rekursywnie grepować?

1682

Jak rekurencyjnie grepwszystkie katalogi i podkatalogi?

find . | xargs grep "texthere" *
wpiri
źródło
110
@ TC1 Smutne jest to, że sam grep może odpowiedzieć na pytanie (przynajmniej GNU grep): grep --help | grep rekurencyjny
Frank Schmitt
7
Jeśli często używasz grep do wyszukiwania rekurencyjnego (zwłaszcza jeśli ręcznie robisz wiele wyłączeń plików / katalogów), może okazać się użyteczne ack (bardzo przyjazna dla programisty alternatywa grep).
Nick McCurdy,
19
W rzeczywistości ani -r, ani -rekursywna praca na polu Solaris, którego używam w pracy. A strona man dla grep nie wspomina nic rekurencyjnego. Musiałem sam się znaleźć i znaleźć xargs.
Ben
8
ag to mój ulubiony sposób na zrobienie tego teraz github.com/ggreer/the_silver_searcher
dranxo
1
grep -rin xlsx *.plnie działa dla mnie w Redhat Linux. Pojawia się błąd „brak dopasowania”.
Sitowie

Odpowiedzi:

2507
grep -r "texthere" .

Pierwszy parametr reprezentuje szukane wyrażenie regularne, a drugi katalog, który należy przeszukać. W takim przypadku .oznacza bieżący katalog.

Uwaga: Działa to w przypadku GNU grep, a na niektórych platformach, takich jak Solaris, musisz w szczególności używać GNU grep zamiast implementacji starszej wersji. W przypadku Solaris jest to ggreppolecenie.

Vinko Vrsalovic
źródło
39
Uwaga: „grep -r” działa tylko na nowszych greps. Nie działa na przykład na grep AIX 5.3.
Wstrzymano
110
Użyj grep -R, aby śledzić dowiązania symboliczne.
Eloff,
53
Dobrze jest wiedzieć, że „-i” spowoduje, że wielkość liter nie będzie rozróżniana, a „-n” również zawiera numer linii dla każdego dopasowanego wyniku.
Sadegh
24
również dobrze wiedzieć, jeśli szukasz tylko stałego ciągu, a nie wyrażenia regularnego, użyj opcji -F. zaoszczędzi ci czasu, nie wywołując parsera wyrażeń regularnych. bardzo przydatny, jeśli przeszukujesz wiele plików.
Jeff
6
alias rgrep = 'grep -r'
zabrał
679

Jeśli znasz rozszerzenie lub wzorzec pliku, który chcesz, inną metodą jest użycie --includeopcji:

grep -r --include "*.txt" texthere .

Możesz także wspomnieć o plikach do wykluczenia --exclude.

Ag

Jeśli często przeszukujesz kod, Ag (The Silver Searcher) jest znacznie szybszą alternatywą dla grep, dostosowaną do wyszukiwania kodu. Na przykład jest domyślnie rekurencyjny i automatycznie ignoruje wymienione w nim pliki i katalogi .gitignore, więc nie musisz ciągle przekazywać tych samych kłopotliwych opcji wykluczania grep lub find.

christangrant
źródło
3
Działa świetnie z grep, który jest dostarczany z Linuxem i Cygwinem, ale nie z tym, który jest dostarczany z AIX.
Wstrzymano
1
@KrzysztofWolny: `` zamiast =działa dobrze na Ubuntu. PS: to ma być przestarzałe miejsce, ale parser znaczników SO nie powiódł się.
Dan Dascalescu,
4
@DanDascalescu Głosowałem za grep, a nie za Ag, po prostu wiesz :)
Bernhard
1
Czy mamy opcję wykluczenia katalogu podczas wyszukiwania rekurencyjnego?
Tom Taylor
Cygwin z Windows lubi podwójne cytaty--include "*.txt" --include "*.TXT"
Bob Stein
127

Również:

find ./ -type f -print0 | xargs -0 grep "foo"

ale grep -rjest lepszą odpowiedzią.

Kurt
źródło
14
Lub jeśli nie chcesz się martwić spacjami w nazwach plików, find . -type f -exec grep "foo" '{}' \;działa dobrze tam, gdzie jest obsługiwane.
Edd Steel
4
Jeśli zamierzasz przeszukiwać przez xargs do grep, A jeśli szukasz tylko stałego ciągu (tj. Nie wyrażenia regularnego), możesz skorzystać z opcji grep -F, aby grep nie ładował silnika wyrażenia regularnego dla każdego wywołania. Jeśli plików jest dużo, będzie to znacznie szybsze.
Jeff
2
odnaleźć . -type f -exec grep -Hu "foo" {} \; to jest to, czego używam, ponieważ daje nazwę pliku.
Wes
Działa to na wszystkich * nix, ponieważ jest to POSIX 7
Ciro Santilli 16 病毒 审查 六四 事件 法轮功
1
find ./ -type f -print0 | xargs -0 grep "foo"
aehlke,
118

Teraz zawsze używam (nawet w systemie Windows z GoW - Gnu w systemie Windows ):

grep --include="*.xxx" -nRHI "my Text to grep" *

Obejmuje to następujące opcje:

--include=PATTERN

Powtarzaj w katalogach, szukając tylko pasujących plików PATTERN.

-n, --line-number

Poprzedź każdą linię wyjścia numerem linii w pliku wejściowym.

(Uwaga: phuclv dodaje w komentarzach , -nco znacznie obniża wydajność , więc możesz chcieć pominąć tę opcję)

-R, -r, --recursive

Czytaj rekursywnie wszystkie pliki w każdym katalogu; jest to równoważne z -d recurseopcją.

-H, --with-filename

Wydrukuj nazwę pliku dla każdego dopasowania.

-I     

Przetwarzaj plik binarny tak, jakby nie zawierał pasujących danych;
jest to równoważne z --binary-files=without-matchopcją.

I mogę dodać ' i' ( -nRHIi), jeśli chcę wyniki bez rozróżniania wielkości liter.

Mogę dostać:

/home/vonc/gitpoc/passenger/gitlist/github #grep --include="*.php" -nRHI "hidden" *
src/GitList/Application.php:43:            'git.hidden'      => $config->get('git', 'hidden') ? $config->get('git', 'hidden') : array(),
src/GitList/Provider/GitServiceProvider.php:21:            $options['hidden'] = $app['git.hidden'];
tests/InterfaceTest.php:32:        $options['hidden'] = array(self::$tmpdir . '/hiddenrepo');
vendor/klaussilveira/gitter/lib/Gitter/Client.php:20:    protected $hidden;
vendor/klaussilveira/gitter/lib/Gitter/Client.php:170:     * Get hidden repository list
vendor/klaussilveira/gitter/lib/Gitter/Client.php:176:        return $this->hidden;
...
VonC
źródło
Gow wygląda obiecująco - nowszy niż narzędzia GNU Windows, których używałem. Próbuję teraz ...
Radim Cernej
jakie jest znaczenie ostatniego znaku * tutaj?
lorniper
2
@lorniper powoduje, że powłoka wybiera wszystkie pliki i foldery w bieżącym katalogu, dzięki czemu grep stosuje się do tych plików i (rekurencyjnie z powodu -Ropcji) do folderów.
VCC
2
@lorniper Noy dokładnie: *lub .jest wzorem globalnym (interpretowanym przez powłokę): unix.stackexchange.com/a/64695/7490 . ' .' wybierze również pliki kropkowe lub foldery kropkowe (jak .git/)
VonC
poprzednio zawsze używałem, grep -rnIale potem nauczyłem się, że -nto znacznie obniża wydajność, więc używam go tylko wtedy, gdy jest naprawdę potrzebny i zwykle używam-rI
phuclv
25

W systemach POSIX nie znajdziesz -rparametru dla grepi grep -rn "stuff" .nie uruchomisz się, ale jeśli użyjesz findpolecenia, to:

find . -type f -exec grep -n "stuff" {} \; -print

Uzgodnione przez Solarisi HP-UX.

wieża
źródło
jakie jest znaczenie {} \; -print odpowiednio?
user1169587 27.04.16
3
W -execopcji - symbol {}jest odniesieniem do nazwy pliku, która jest aktualnie znaleziona przez findnarzędzie (to znaczy, aby coś zrobić z nazwą pliku, którą znaleźliśmy), również -execopcja powinna być zakończona ;symbolem (aby oznaczyć koniec poleceń exec), ale ponieważ to wszystko działający w powłoce, ten symbol powinien być poprzedzony znakiem ucieczki .. i na koniec -printopcja pozwala finddrukować na ekranie znalezione nazwy plików.
wieża
19

globbing **

Używanie grep -rdziała, ale może przesadzać, szczególnie w dużych folderach.

Dla bardziej praktycznego zastosowania, oto składnia, która używa składni globbing ( **):

grep "texthere" **/*.txt

który greps tylko określone pliki z wybranym wzorem wzorca. Działa z obsługiwanymi powłokami, takimi jak Bash +4 lub zsh .

Aby aktywować tę funkcję, należy uruchomić: shopt -s globstar.

Zobacz także: Jak znaleźć wszystkie pliki zawierające określony tekst w systemie Linux?

git grep

W przypadku projektów pod kontrolą wersji Git użyj:

git grep "pattern"

co jest znacznie szybsze.

ripgrep

W przypadku większych projektów najszybszym narzędziem grepping jest ripgrepdomyślnie które pliki greps są rekurencyjnie:

rg "pattern" .

Jest zbudowany na silniku wyrażeń regularnych Rust, który wykorzystuje skończone automaty, SIMD i agresywne optymalizacje dosłowne, aby wyszukiwanie było bardzo szybkie. Sprawdź szczegółową analizę tutaj .

kenorb
źródło
3
Dzięki za sugestię git grep - jest bardzo przydatna i nie wiedziałem o tym!
Basya
2
Dzięki za sugestię ripgrep. Jest o wiele szybszy.
What Cool Be
11

Aby znaleźć nazwę filesz pathrekurencyjnie zawierającą dane stringpolecenie poniżej, użyj dla UNIX:

find . | xargs grep "searched-string"

dla Linux:

grep -r "searched-string" .

znajdź plik na UNIXserwerze

find . -type f -name file_name

znajdź plik na serwerze LINUX

find . -name file_name
Girdhar Singh Rathore
źródło
11

Przydatne mogą być tylko nazwy plików

grep -r -l "foo" .
chim
źródło
10

Jeśli chcesz śledzić tylko rzeczywiste katalogi, a nie dowiązania symboliczne,

grep -r "thingToBeFound" directory

Jeśli chcesz podążać za dowiązaniami symbolicznymi oraz rzeczywistymi katalogami (uważaj na nieskończoną rekurencję),

grep -R "thing to be found" directory

Ponieważ próbujesz rekurencyjnie grep, przydatne mogą być również następujące opcje:

-H: outputs the filename with the line

-n: outputs the line number in the file

Więc jeśli chcesz znaleźć wszystkie pliki zawierające Dartha Vadera w bieżącym katalogu lub dowolnych podkatalogach i przechwycić nazwę pliku i numer linii, ale nie chcesz, aby rekursja podążała za dowiązaniami symbolicznymi, polecenie będzie

grep -rnH "Darth Vader" .

Jeśli chcesz znaleźć wszystkie wzmianki o słowie kot w katalogu

/home/adam/Desktop/TomAndJerry 

i jesteś obecnie w katalogu

/home/adam/Desktop/WorldDominationPlot

i chcesz przechwycić nazwę pliku, ale nie numer wiersza żadnego wystąpienia ciągu „koty”, i chcesz, aby rekursja podążała za dowiązaniami symbolicznymi, jeśli je znajdzie, możesz wykonać jedną z następujących czynności

grep -RH "cats" ../TomAndJerry                   #relative directory

grep -RH "cats" /home/adam/Desktop/TomAndJerry   #absolute directory

Źródło:

uruchamianie „grep --help”

Krótkie wprowadzenie do symbolicznych linków, dla każdego, kto czyta tę odpowiedź i jest zdezorientowany moim odniesieniem do nich: https://www.nixtutor.com/freebsd/understanding-symbolic-links/

SarcasticSully
źródło
Świetna odpowiedź. Dodatkowe przełączniki (-rnh) są bardzo pomocne, więc dziękuję za sugestie.
semtex41
8

ag to mój ulubiony sposób na zrobienie tego teraz github.com/ggreer/the_silver_searcher . Jest to w zasadzie to samo co potwierdzenie, ale z kilkoma dodatkowymi optymalizacjami.

Oto krótki punkt odniesienia. Wyczyszczam pamięć podręczną przed każdym testem (por. Https://askubuntu.com/questions/155768/how-do-i-clean-or-disable-the-memory-cache )

ryan@3G08$ sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
3
ryan@3G08$ time grep -r "hey ya" .

real    0m9.458s
user    0m0.368s
sys 0m3.788s
ryan@3G08:$ sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
3
ryan@3G08$ time ack-grep "hey ya" .

real    0m6.296s
user    0m0.716s
sys 0m1.056s
ryan@3G08$ sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
3
ryan@3G08$ time ag "hey ya" .

real    0m5.641s
user    0m0.356s
sys 0m3.444s
ryan@3G08$ time ag "hey ya" . #test without first clearing cache

real    0m0.154s
user    0m0.224s
sys 0m0.172s
dranxo
źródło
6

To powinno działać:

grep -R "texthere" *
sumit kumar
źródło
6

Jeśli szukasz określonej zawartości we wszystkich plikach ze struktury katalogów, możesz użyć, findponieważ jest bardziej jasne, co robisz:

find -type f -exec grep -l "texthere" {} +

Zauważ, że -l(mała litera L) pokazuje nazwę pliku zawierającego tekst. Usuń go, jeśli zamiast tego chcesz wydrukować sam mecz. Lub użyj, -Haby zebrać plik razem z dopasowaniem. Wszystkie inne alternatywy to:

find -type f -exec grep -Hn "texthere" {} +

Gdzie -ndrukuje numer linii.

fedorqui „SO przestań szkodzić”
źródło
2
Up-głosowało za to, że jedynym findrozwiązaniem zarówno uniknąć niepotrzebnego używania xargsi używać +zamiast \;z -exec, unikając w ten sposób mnóstwo niepotrzebnych startów procesowych. :-)
ShadowRanger
6

Ten działał w moim przypadku na mojej bieżącej maszynie (git bash na Windows 7):

find ./ -type f -iname "*.cs" -print0 | xargs -0 grep "content pattern"

Zawsze zapominam o -print0 i -0 dla ścieżek ze spacjami.

EDYCJA: Moim preferowanym narzędziem jest teraz ripgrep: https://github.com/BurntSushi/ripgrep/releases . Jest naprawdę szybki i ma lepsze ustawienia domyślne (takie jak domyślnie rekurencyjne). Taki sam przykład, jak w mojej oryginalnej odpowiedzi, ale przy użyciu ripgrep:rg -g "*.cs" "content pattern"

arkod
źródło
4

grep -r "texthere" . (okres wypowiedzenia na końcu)

(^ kredyt: https://stackoverflow.com/a/1987928/1438029 )


Wyjaśnienie:

grep -r "texthere" /(rekurencyjnie grepuj wszystkie katalogi i podkatalogi)

grep -r "texthere" .(rekurencyjnie grep te katalogi i podkatalogi)

grep rekurencyjny

grep [options] PATTERN [FILE...]

[opcje]

-R, -r, --recursive

Odczytuj rekurencyjnie wszystkie pliki w każdym katalogu.

Jest to równoważne z opcją -d recurselub --directories=recurse.

http://linuxcommand.org/man_pages/grep1.html

grep help

$ grep --help

$ grep --help |grep recursive
  -r, --recursive           like --directories=recurse
  -R, --dereference-recursive

Alternatywy

ack( http://beyondgrep.com/ )

ag( http://github.com/ggreer/the_silver_searcher )

Geoffrey Hale
źródło
4

W 2018 roku chcesz użyć ripgreplub the-silver-searcherponieważ są one znacznie szybsze niż alternatywy.

Oto katalog z 336 podkatalogami pierwszego poziomu:

% find . -maxdepth 1 -type d | wc -l
     336

% time rg -w aggs -g '*.py'
...
rg -w aggs -g '*.py'  1.24s user 2.23s system 283% cpu 1.222 total

% time ag -w aggs -G '.*py$'
...
ag -w aggs -G '.*py$'  2.71s user 1.55s system 116% cpu 3.651 total

% time find ./ -type f -name '*.py' | xargs grep -w aggs
...
find ./ -type f -name '*.py'  1.34s user 5.68s system 32% cpu 21.329 total
xargs grep -w aggs  6.65s user 0.49s system 32% cpu 22.164 total

Na OSX, to instaluje ripgrep: brew install ripgrep. Instaluje silver-searcher: brew install the_silver_searcher.

Hughdbrown
źródło
Szybkość jest ważna, jeśli musisz to robić często, ale większość z nas robi to tylko kilka razy w roku. Zainstalowanie najnowszego narzędzia do robienia juju innych firm jest zbyt przesadne, a rozwiązania, które niewiele się zmieniły od 1978 r., Warto poznać niezależnie.
tripleee
Uważam za wysoce nieprawdopodobne, aby programista szukał tekstu w drzewie źródłowym tylko kilka razy w roku. Ale nawet z punktu widzenia użyteczności rgma znaczną przewagę nad łączeniem rekurencyjnego polecenia grep od zera. Używanie rg: rg foo. Korzystanie z narzędzi UNIX: find . | xargs grep foo. A jeśli któryś z twoich plików zawiera cytat, musisz go użyć find . -print0 | xargs -0 grep foo. Czy pamiętasz, że jeśli używasz tego kilka razy w roku?
hughdbrown,
1
Zapominasz, find . -type f -exec grep 'regex' {} +co jest naprawdę łatwe do zapamiętania, jeśli używasz tych narzędzi z dowolną regularnością. Ale prawdopodobnie i tak powinieneś uruchomić ctagslub etagsna drzewie źródłowym, jeśli chcesz często znajdować rzeczy.
tripleee
Korzystam z ripgrep i jest świetny. Ale srebrny program do wyszukiwania jest fantastyczny dla programistów. +1
Matt
3

Na moim serwerze IBM AIX (wersja systemu operacyjnego: AIX 5.2) użyj:

find ./ -type f -print -exec grep -n -i "stringYouWannaFind" {} \; 

spowoduje to wydrukowanie ścieżki / nazwy pliku i względnego numeru linii w pliku, takich jak:

./inc/xxxx_x.h

2865: / ** Opis: stringYouWannaFind * /

w każdym razie to działa dla mnie :)

użytkownik3606336
źródło
3

Poniżej znajduje się polecenie wyszukiwania Stringrekurencyjnie włączone Unixi Linuxśrodowisko.

dla UNIXpolecenia jest:

find . -name "string to be searched" -exec grep "text" "{}" \;

dla Linuxpolecenia jest:

grep -r "string to be searched" .
Girdhar Singh Rathore
źródło
2

Aby uzyskać listę dostępnych flag:

grep --help 

Zwraca wszystkie dopasowania tekstu regularnego w bieżącym katalogu z odpowiednim numerem wiersza:

grep -rn "texthere" .

Zwraca wszystkie dopasowania tekstu tekstowego , zaczynając od katalogu głównego, z odpowiednim numerem wiersza i ignorując wielkość liter:

grep -rni "texthere" /

flagi użyte tutaj:

  • -r rekurencyjny
  • -n wypisz numer wiersza z wyjściem
  • -i zignoruj ​​wielkość liter
JSON C11
źródło
1

Myślę, że to właśnie próbujesz napisać

grep myText $(find .)

i może to być coś innego, jeśli chcesz znaleźć grep hit

grep myText $(find .) | cut -d : -f 1 | sort | uniq
Victor Faria
źródło
Jest bardzo intuicyjny: na przykład: grep -i acc $ (find. -Name "wykonanie *. *")
Yu Shen
1

Rzucam tutaj moje dwa centy. Jak już wspomniano inni grep -r nie działa na każdej platformie. Może to zabrzmieć głupio, ale zawsze używam git.

git grep "texthere"

Nawet jeśli katalog nie jest przemieszczany, po prostu go wystawiam i używam git grep.

Zstack
źródło
0

Zwróć uwagę, że find . -type f | xargs grep whateverw przypadku zbyt wielu plików pasujących do funkcji find różne rodzaje rozwiązań będą napotykać błędy „Lista argumentów zbyt długa”.

Najlepszym rozwiązaniem jest, grep -rale jeśli to nie jest dostępne, użyj find . -type f -exec grep -H whatever {} \;zamiast tego.

m. thome
źródło
Co? xargsjest w szczególności obejściem problemu „Zbyt długa lista argumentów”.
tripleee
2
Cóż, nie - xargs jest specjalnie przeznaczony do konwertowania potoku argumentów na arglistę, ale tak, prawdą jest, że nowoczesne xargs, gdy są używane z -s i / lub -L, mogą radzić sobie z bardzo długimi arglistami, dzieląc się na wiele wywołań poleceń, ale nie jest skonfigurowane w ten sposób domyślnie (i nie było żadnej z powyższych odpowiedzi). Jako przykład:find . -type f | xargs -L 100 grep whatever
m.thome
Na jakiej platformie by to było? POSIXxargs jest znormalizowany, aby takie zachowanie było gotowe. xargsNarzędzie ogranicza długość wiersza poleceń, tak aby przy wywołaniu wiersza poleceń połączone listy argumentów i środowiska ... nie przekraczały {ARG_MAX} -2048 bajtów.”
tripleee
Hm Chociaż dokumenty GNU są na tej podstawie mniej jasne niż POSIX i nie mam już dostępu do maszyny, która spowodowała, że ​​złożyłem to oświadczenie, nie mogę potwierdzić mojej oryginalnej interpretacji na temat żadnej bieżącej implementacji. Oczywiście rekurencyjne grep jest nadal preferowane, jeśli jest dostępne, ale nie ma powodu, aby unikać przepisu xargs (użyj -H dla grep, aby uniknąć ostatecznego wywołania grep, który przejdzie tylko jedna nazwa pliku).
m.thome
0

Dla zabawy szybkie i nieprzyzwoite wyszukiwanie plików * .txt, jeśli odpowiedź na @christangrant jest zbyt duża :-)

grep -r texthere .|grep .txt

PJ Brunet
źródło
0

Oto funkcja rekurencyjna (przetestowana lekko za pomocą bash i sh), która przegląda wszystkie podfoldery danego folderu (1 USD) i używa grepwyszukiwania podanego ciągu (3 USD) w podanych plikach (2 USD):

$ cat script.sh
#!/bin/sh

cd "$1"

loop () {
    for i in *
    do
        if [ -d "$i" ]
        then
            # echo entering "$i"
            cd "$i"
            loop "$1" "$2"
        fi
    done

    if [ -f "$1" ]
    then
        grep -l "$2" "$PWD/$1"
    fi

    cd ..
}

loop "$2" "$3"

Uruchomienie i przykładowe wyjście:

$ sh script start_folder filename search_string
/home/james/start_folder/dir2/filename
James Brown
źródło
-2
The syntax is:
cd /path/to/dir
grep -r <"serch_word name"> .
Poo
źródło
7
To niewiele dodaje do innych odpowiedzi
Mel