Użyj składni grep --exclude / - include, aby nie grepować przez niektóre pliki

779

Szukam ciągu foo=w plikach tekstowych w drzewie katalogów. Jest na wspólnej maszynie z Linuksem, mam powłokę bash:

grep -ircl "foo=" *

W katalogach znajduje się także wiele plików binarnych pasujących do „foo =”. Ponieważ te wyniki nie są istotne i spowalniają wyszukiwanie, chcę, aby grep pomijał wyszukiwanie tych plików (głównie obrazy JPEG i PNG). Jak mam to zrobić?

Wiem, że istnieją opcje --exclude=PATTERNi --include=PATTERN, ale jaki jest format wzoru? Strona man grep mówi:

--include=PATTERN     Recurse in directories only searching file matching PATTERN.
--exclude=PATTERN     Recurse in directories skip file matching PATTERN.

Wyszukiwanie w grep włącz , grep włącz wyklucz , grep wyklucz i warianty nie znalazły nic istotnego

Jeśli istnieje lepszy sposób na grepowanie tylko w niektórych plikach, jestem za tym; przeniesienie niepoprawnych plików nie jest opcją. Nie mogę przeszukiwać tylko niektórych katalogów (struktura katalogów to wielki bałagan, wszystko jest wszędzie). Ponadto nie mogę niczego zainstalować, więc muszę zrobić ze zwykłymi narzędziami (takimi jak grep lub sugerowane znalezisko ).

Piskvor opuścił budynek
źródło
13
Po prostu FYI, użyte argumenty: -c policz dopasowania w pliku -i bez rozróżniania wielkości liter -l pokaż tylko pasujące pliki -r rekurencyjne
Piskvor opuścił budynek
68
Szybszym sposobem na wykluczenie katalogów svn jest --exclude-dir=.svn, aby grep w ogóle do nich nie wchodził
orip
25
Kilka pedantycznych punktów, które ludzie powinni wiedzieć: 1. Zwróć uwagę na brak cytatów na całym świecie: --exclude = ' . {Png, jpg}' nie działa (przynajmniej w mojej wersji GNU grep), ponieważ grep nie obsługuje {} w swoich globach. Powyższe jest rozwinięte w powłoce do '--exclude = .png --exclude = *. Jpg' (przy założeniu, że pliki nie pasują do cwd - bardzo mało prawdopodobne, ponieważ zwykle nie zaczynasz nazw plików z '--exclude ='), które grep lubi dobrze. 2. --exclude jest rozszerzeniem GNU i nie jest częścią definicji grep POSIX, więc jeśli piszesz skrypty używając tego, pamiętaj, że niekoniecznie będą działały w systemach innych niż GNU.
ijw 20.01.11
2
Pełny przykład użycia exclude-dir:grep -r --exclude-dir=var "pattern" .
Tisch

Odpowiedzi:

766

Użyj składni globowania powłoki:

grep pattern -r --include=\*.{cpp,h} rootdir

Składnia dla --excludejest identyczna.

Zauważ, że gwiazdę ucieka odwrotnym ukośnikiem, aby zapobiec jej rozszerzeniu przez powłokę (cytowanie jej, na przykład --include="*.{cpp,h}", działałoby równie dobrze). W przeciwnym razie, jeśli w bieżącym katalogu roboczym byłyby jakieś pliki, które pasowałyby do wzorca, wiersz poleceń rozwinąłby się do czegoś takiego grep pattern -r --include=foo.cpp --include=bar.h rootdir, co przeszukiwałoby tylko pliki o nazwach foo.cppi bar.h, co prawdopodobnie nie jest tym, czego chciałeś.

Adam Rosenfield
źródło
8
Nie wiem dlaczego, ale musiałem zacytować wzór dołączania w następujący sposób:grep pattern -r --include="*.{cpp,h}" rootdir
topek,
6
@topek: Dobra uwaga - jeśli masz jakieś pliki .cpp / .h w bieżącym katalogu, wówczas powłoka rozszerzy glob przed wywołaniem grep, więc skończysz z wierszem poleceń podobnym do grep pattern -r --include=foo.cpp --include=bar.h rootdir, który przeszuka tylko pliki o nazwie foo.cpplub bar.h. Jeśli nie masz żadnych plików, które pasują do glob w bieżącym katalogu, powłoka przekazuje glob do grep, co poprawnie interpretuje.
Adam Rosenfield
6
Właśnie zdałem sobie sprawę, że glob jest przyzwyczajony do dopasowywania tylko nazwy pliku. Aby wykluczyć cały katalog, potrzebna jest --exclude-diropcja. Obowiązują jednak te same zasady. Dopasowywana jest tylko nazwa pliku katalogu, a nie ścieżka.
Krzysztof Jabłoński
3
--includewydaje się nie działać po --exclude. Podejrzewam, że nie ma sensu nawet próbować, z wyjątkiem tego, że mam aliasgrep z długą listą --excludei --exclude-dir, której używam do wyszukiwania kodu, ignorowania bibliotek i zamiany plików i innych rzeczy. Miałem nadzieję, że grep -r --exclude='*.foo' --include='*.bar'to zadziała, więc mógłbym ograniczyć moje tylko aliasdo --include='*.bar', ale wydaje się, że ignoruje --includei zawiera wszystko, co nie jest plikiem .foo. Zamiana kolejności --includei --excludedziała, ale niestety to nie pomaga w moim przypadku alias.
Michael Scheper,
1
jak możemy odczytać czyjś umysł, aby uzyskać zasady dotyczące tego PATTERN. Pół godziny nie mogę znaleźć żadnego opisu tego, na co tam czekają
Arkady
221

Jeśli chcesz po prostu pominąć pliki binarne, proponuję spojrzeć na -Iopcję (wielkie litery i). Ignoruje pliki binarne. Regularnie używam następującego polecenia:

grep -rI --exclude-dir="\.svn" "pattern" *

Przeszukuje rekurencyjnie, ignoruje pliki binarne i nie zagląda do ukrytych folderów Subversion pod kątem dowolnego wzoru. Mam alias jako „grepsvn” na moim pudełku w pracy.

rmeador
źródło
1
Dzięki, to bardzo przydatne w niektórych innych scenariuszach, które napotkałem.
Piskvor opuścił budynek
25
--exclude-dirnie jest dostępne wszędzie. moje pole RH w pracy z GNU grep 2.5.1 go nie ma.
gcb
Wszelkie sugestie dotyczące tego, co stosować, gdy --exclude-dirjest niedostępne? We wszystkich moich próbach --excludewydaje się nie pasować do rachunku.
JMTyler
Zawsze możesz pobrać najnowsze źródło grep z GNU i wykonać konfigurację; robić; sudo make install ”. To jedna z pierwszych rzeczy, które robię na komputerze Mac lub starszej dystrybucji Linunx.
Jonathan Hartley,
3
Dokładnie to, czego potrzebowałem. Właściwie używam git. Więc --exclude-dir="\.git". :-)
Ionică Bizău,
66

Proszę spojrzeć na ack , który jest przeznaczony do dokładnie takich sytuacji. Twój przykład

grep -ircl --exclude=*.{png,jpg} "foo=" *

odbywa się za pomocą ack as

ack -icl "foo="

ponieważ potwierdzenie nigdy nie przegląda plików binarnych, a opcja -r jest domyślnie włączona. A jeśli chcesz tylko pliki CPP i H, po prostu zrób

ack -icl --cpp "foo="
Andy Lester
źródło
Wygląda nieźle, następnym razem wypróbuje samodzielną wersję Perla, dzięki.
Piskvor opuścił budynek
5
Dobry telefon, nie mogę dłużej żyć bez potwierdzenia.
Szansa
1
stackoverflow.com/questions/667471/… - Pozwoli ci to uzyskać potwierdzenie w systemie Windows, jeśli z tego miejsca korzystasz z grep.
TamusJRoyce,
@Chance Może chcesz silversearcher-ag , tylko apt-getw Ubuntu :)
Justme0 18.04.2016
nie mylićawk
jasonleonhard
35

grep 2.5.3 wprowadził parametr --exclude-dir, który będzie działał tak, jak chcesz.

grep -rI --exclude-dir=\.svn PATTERN .

Możesz także ustawić zmienną środowiskową: GREP_OPTIONS = "- exclude-dir = .svn"

Zaraz sekundy Andy'ego zagłosuj na ACK jednak, że jest to najlepsze.

Corey
źródło
7
+1 za podanie dokładnego numeru wersji; Mam grep 2.5.1 i opcja exclude-dir nie jest dostępna
James
25

Znalazłem to po długim czasie, możesz dodać wiele włączeń i wykluczeń, takich jak:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js
Rushabh Mehta
źródło
5
Lepiej połączyć je na liście takiej jak: --exclude = {wzorzec1, wzorzec2, wzorzec3}
Yasser Sinjab
12

Sugerowane polecenie:

grep -Ir --exclude="*\.svn*" "pattern" *

jest błędne koncepcyjnie, ponieważ --exclude działa na basenieame. Innymi słowy, pominie tylko .svn w bieżącym katalogu.


źródło
3
Tak, dla mnie to wcale nie działa. Ten, który pracował dla mnie to: exclude-dir = .svn
Taryn East
2
@Nicola dziękuję! Odrywam włosy od tego, dlaczego to nie zadziała. Powiedz mi, czy jest sposób, aby to odkryć na stronie podręcznika? Mówi tylko, że pasuje do „WZÓR”. EDYCJA strony podręcznika mówi „plik”, jak wyjaśniono tutaj fixunix.com/unix/…
13ren
11

W grep 2.5.1 musisz dodać tę linię do profilu ~ / .bashrc lub ~ / .bash

export GREP_OPTIONS="--exclude=\*.svn\*"
deric
źródło
9

Uważam, że wyjście grepping grep jest bardzo pomocne:

grep -rn "foo=" . | grep -v "Binary file"

Chociaż tak naprawdę nie powstrzymuje go to od przeszukiwania plików binarnych.

Aaron Maenpaa
źródło
10
Możesz użyć grep -Ido pominięcia plików binarnych.
Nathan Fellman
Zrobiłem to również, gdy byłem młody ... teraz wiem lepiej i kiedy mam do czynienia z problemem, pierwszą rzeczą jest RTFM
gcb
grepping grep usunie rozjaśnienia kolorów.
Max Li
7

Jeśli nie masz nic przeciwko używaniu find, podoba mi się jego -prunefunkcja:

find [directory] \
        -name "pattern_to_exclude" -prune \
     -o -name "another_pattern_to_exclude" -prune \
     -o -name "pattern_to_INCLUDE" -print0 \
| xargs -0 -I FILENAME grep -IR "pattern" FILENAME

W pierwszym wierszu określasz katalog, który chcesz przeszukać. .(bieżący katalog) to na przykład poprawna ścieżka.

Na 2. i 3. linii, użyj "*.png", "*.gif", "*.jpg", i tak dalej. Użyj tyle -o -name "..." -prunekonstrukcji, ile masz wzorów.

Na 4 linii, trzeba inny -o(określa ona „lub” find), wzorce Ty chcesz, i trzeba albo -printczy -print0na końcu. Jeśli chcesz po prostu „wszystko inne”, która pozostaje po przycinanie *.gif, *.pngitd obrazów, a następnie użyć -o -print0i skończysz z 4 linii.

Wreszcie w piątym wierszu jest potok, do xargsktórego pobiera każdy z wynikowych plików i przechowuje je w zmiennej FILENAME. Następnie przechodzi grepdo -IRflagi, "pattern", a następnie FILENAMErozszerza się przez xargsstać, że lista nazw znaleźć find.

W przypadku konkretnego pytania oświadczenie może wyglądać mniej więcej tak:

find . \
     -name "*.png" -prune \
     -o -name "*.gif" -prune \
     -o -name "*.svn" -prune \
     -o -print0 | xargs -0 -I FILES grep -IR "foo=" FILES

OnlineCop
źródło
Jedna poprawka, którą zasugeruję: uwzględnij -falsenatychmiast po każdej, -prunewięc zapomnienie użycia -print0lub jakieś execpolecenie nie spowoduje wydrukowania plików, które chcesz wykluczyć: -name "*.png" -prune -false -o name "*.gif -prune -false...
OnlineCop
7

W CentOS 6.6 / Grep 2.6.3 muszę go używać w następujący sposób:

grep "term" -Hnir --include \*.php --exclude-dir "*excluded_dir*"

Zwróć uwagę na brak równych znaków „=” (inaczej --include, --exclude, include-diri --exclude-dirsą ignorowane)

aesede
źródło
6

git grep

Użyj, git grepktóry jest zoptymalizowany pod kątem wydajności i ma na celu wyszukiwanie w niektórych plikach.

Domyślnie ignoruje pliki binarne i honoruje twoje .gitignore. Jeśli nie pracujesz ze strukturą Git, nadal możesz z niej korzystać, przechodząc --no-index.

Przykładowa składnia:

git grep --no-index "some_pattern"

Aby uzyskać więcej przykładów, zobacz:

kenorb
źródło
5

Oczywiście jestem dyletantem, ale oto jak wygląda mój ~ / .bash_profile:

eksportuj GREP_OPTIONS = "- orl --exclude-dir = .svn --exclude-dir = .cache --color = auto" GREP_COLOR = '1; 32'

Zauważ, że aby wykluczyć dwa katalogi, musiałem dwukrotnie użyć opcji --exclude-dir.

4D4M
źródło
3

Jeśli wyszukujesz nierekurencyjnie, możesz użyć wzorców Glop, aby dopasować nazwy plików.

grep "foo" *.{html,txt}

zawiera html i txt. Przeszukuje tylko bieżący katalog.

Aby wyszukać w podkatalogach:

   grep "foo" */*.{html,txt}

W podkatalogach:

   grep "foo" */*/*.{html,txt}
Stéphane Laurent
źródło
3

W katalogach znajduje się także wiele plików binarnych. Nie mogę przeszukiwać tylko niektórych katalogów (struktura katalogów to duży bałagan). Czy jest lepszy sposób na grepowanie tylko w niektórych plikach?

ripgrep

Jest to jedno z najszybszych narzędzi zaprojektowanych do rekurencyjnego przeszukiwania bieżącego katalogu. Jest napisany w języku Rust , zbudowanym na silniku regularnym Rust, aby uzyskać maksymalną wydajność. Sprawdź szczegółową analizę tutaj .

Możesz więc po prostu uruchomić:

rg "some_pattern"

Szanuje twoje .gitignorei automatycznie pomija ukryte pliki / katalogi i pliki binarne.

Nadal możesz dostosowywać dołączanie lub wykluczanie plików i katalogów za pomocą -g/ --glob. Reguły .gitignoreglobowania odpowiadają globom. Sprawdź man rgpomoc.

Aby uzyskać więcej przykładów, zobacz: Jak wykluczyć niektóre pliki niezgodne z niektórymi rozszerzeniami z grep?

W systemie macOS można zainstalować za pośrednictwem brew install ripgrep.

kenorb
źródło
3

znajdź i xargs są twoimi przyjaciółmi. Użyj ich do filtrowania listy plików zamiast grep's --exclude

Spróbuj czegoś takiego

find . -not -name '*.png' -o -type f -print | xargs grep -icl "foo="

Zaletą przyzwyczajenia się do tego jest to, że można go rozszerzyć na inne przypadki użycia, na przykład do zliczania linii we wszystkich plikach innych niż png:

find . -not -name '*.png' -o -type f -print | xargs wc -l

Aby usunąć wszystkie pliki inne niż PNG:

find . -not -name '*.png' -o -type f -print | xargs rm

itp.

Jak wskazano w komentarzach, jeśli niektóre pliki mogą mieć spacje w swoich nazwach, użyj -print0i xargs -0zamiast.

Andrew Stein
źródło
1
Nie działa to na nazwy plików ze spacjami, ale problem ten można łatwo rozwiązać, używając print0 zamiast print i dodając opcję -0 do xargs.
Adam Rosenfield
2

te skrypty nie rozwiązują całego problemu ... Spróbuj tego lepiej:

du -ha | grep -i -o "\./.*" | grep -v "\.svn\|another_file\|another_folder" | xargs grep -i -n "$1"

ten skrypt jest o wiele lepszy, ponieważ używa „prawdziwych” wyrażeń regularnych, aby uniknąć wyszukiwania katalogów. po prostu oddziel nazwy folderów lub plików za pomocą „\ |” na grep -v

ciesz się! znalezione na mojej powłoce linux! XD


źródło
2

Spójrz @ ten.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags
Suhas Tawade
źródło
2
Rzeczy, które osiągają to w przybliżeniu, zostały omówione w innych postach; co więcej, jest to złe, ponieważ przy różnych ustawionych opcjach układu będzie bałaganił numery linii i tego typu rzeczy lub wykluczył pożądane linie kontekstu.
Chris Morgan,
jak możesz używać kilku opcji „-v” jednocześnie?
Otwórz drogę
1

--binary-files=without-matchOpcja GNU grepdostaje to, aby pominąć pliki binarne. (Odpowiednik -Iprzełącznika wymienionego gdzie indziej.)

(Może to wymagać najnowszej wersji grep; przynajmniej 2.5.3.)

mjs
źródło
1

nadaje się do pliku .alias tcsh:

alias gisrc 'grep -I -r -i --exclude="*\.svn*" --include="*\."{mm,m,h,cc,c} \!* *'

Trochę mi zajęło ustalenie, że część {mm, m, h, cc, c} NIE powinna znajdować się w cudzysłowie. ~ Keith

Keith Knauber
źródło
0

Aby zignorować wszystkie wyniki binarne z grep

grep -Ri "pattern" * | awk '{if($1 != "Binary") print $0}'

Część awk odfiltruje wszystkie wiersze pliku binarnego foo

lathomas64
źródło
-2

Spróbuj tego:

  1. Utwórz folder o nazwie „ --F” pod currdir .. (lub połącz inny folder o nazwie „ --F”, tj double-minus-F.
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
P Stos
źródło