Jak rekursywnie grepować?


1682

Jak rekurencyjnie grepwszystkie katalogi i podkatalogi?

find . | xargs grep "texthere" *

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.


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.


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ą.


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;
...

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.


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 .


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

11

Przydatne mogą być tylko nazwy plików

grep -r -l "foo" .

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/


Ś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


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.


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"


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 )


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.


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 :)


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" .

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

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

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.


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.


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


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

-2
The syntax is:
cd /path/to/dir
grep -r <"serch_word name"> .

7
To niewiele dodaje do innych odpowiedzi
Mel
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.