jak używać opcji grep --include dla wielu typów plików?

98

Kiedy chcę grepować wszystkie pliki html w jakimś katalogu, wykonuję następujące czynności

grep --include="*.html" pattern -R /some/path

co działa dobrze. Problem w tym, jak grepować wszystkie pliki html, htm, php w jakimś katalogu?

Z tego Użyj grep --exclude / - include składnię, aby nie przeszukiwać niektórych plików , wydaje się, że mogę wykonać następujące czynności

grep --include="*.{html,php,htm}" pattern -R /some/path

Ale niestety to nie zadziała dla mnie.
FYI, moja wersja grep to 2.5.1.

tianyapiaozi
źródło

Odpowiedzi:

139

Możesz użyć wielu --includeflag. To działa dla mnie:

grep -r --include=*.html --include=*.php --include=*.htm "pattern" /some/path/

Możesz jednak zrobić zgodnie z Deruijtersugestią. To działa dla mnie:

grep -r --include=*.{html,php,htm} "pattern" /some/path/

Nie zapominaj, że możesz użyć findi xargsdo tego typu rzeczy:

find /some/path/ -name "*.htm*" -or -name "*.php" | xargs grep "pattern"

HTH

Steve
źródło
1
Widzę problem. Użyłem --include = " . {Html, php}", aby zapobiec rozszerzaniu się powłoki ' ', co jednocześnie zatrzymuje rozszerzanie powłoki {html, php}. Wygląda na to, że znak równości --include = * jest w stanie zapobiec rozszerzaniu się powłoki „*”.
tianyapiaozi
xargs tak naprawdę nie zastępuje; Wiele razy, gdy potrzebujesz tej funkcji, masz do czynienia z większą liczbą plików, niż obsłuży xargs.
James Moore
2
@JamesMoore: Spójrz na GNU Parallel . Często może być używany jako substytut xargs. To jest również warto szybki odczyt. HTH.
Steve
3
@tianyapiaozi: Masz rację, że problem stanowi cytowanie wokół rozszerzenia nawiasów klamrowych; bez cytowania jednak *nadal podlega globbingowi jako część tokenu, w którym jest osadzony , po prostu zdarza się , że w tym przypadku nie pasuje do niczego, ponieważ pasowałyby tylko pliki o dosłownej nazwie podobnej --include=foo.html. Aby być bezpiecznym, zacytuj *(który możesz zrobić indywidualnie \*). Jako dodatkowy bonus sprawia to wizualnie wyraźniejsze, że to nie powłoka powinna wykonywać globbing w tym przypadku.
mklement0
2
Jeśli chodzi o findrozwiązanie: używanie -exec grep "pattern" {} +zamiast | xargs grep "pattern"jest bardziej niezawodne (obsługuje na przykład nazwy plików ze spacjami), a także bardziej wydajne.
mklement0
32

Korzystanie {html,php,htm}może pracować tylko jako rozszerzenie usztywniającym , który jest nietypowa (nie POSIX) cechą bash, kshi zsh.

  • Innymi słowy: nie próbuj używać go w skrypcie, który jest przeznaczony /bin/sh- w takim przypadku użyj jawnych wielu --includeargumentów.

  • grepsama nie rozumie {...}notacji.

Aby interpretacja nawiasów została rozpoznana, musi to być niecytowany (część) token w wierszu poleceń.

Rozwinięcie nawiasów klamrowych rozszerza się do wielu argumentów , więc w omawianym przypadku grepkończy się wyświetleniem wielu --include=... opcji, tak jakbyś przeszedł je indywidualnie.

Wyniki rozwijania nawiasów klamrowych podlegają globalizacji (rozwijaniu nazw plików) , co ma pułapki :

  • Każdą otrzymaną argument można dodatkowo rozszerzyć do dopasowania nazwami jeśli zdarzy się, że zawiera nienotowanych metaznaki plików takich jak *.
    Chociaż jest to mało prawdopodobne w przypadku tokenów, takich jak --include=*.html(np. Musiałbyś mieć plik o dosłownie nazwie podobnej --include=foo.htmldo czegoś, co ma pasować), warto o tym ogólnie pamiętać.

  • Jeśli nullglobopcja powłoki jest włączona ( shopt -s nullglob) i globbing nie pasuje do niczego , argument zostanie odrzucony .

Dlatego, aby uzyskać w pełni solidne rozwiązanie , użyj następujących elementów:

grep -R '--include=*.'{html,php,htm} pattern /some/path
  • '--include=*.'jest traktowany jako literał , ponieważ występuje w pojedynczym cudzysłowie ; zapobiega to nieumyślnej interpretacji *jako globbing postaci.

  • {html,php,htm}The - konieczności - niecytowany rozszerzalności usztywniającym [1] , rozszerza się 3 argumentów, które ze względu na {...} następujące bezpośrednio po '...'żeton , zawierających ten symbol.

  • Dlatego po usunięciu cytatu przez powłokę, następujące 3 dosłowne argumenty są ostatecznie przekazywane dogrep :

    • --include=*.html
    • --include=*.php
    • --include=*.htm

[1] Dokładniej, tylko te części rozwinięcia nawiasów klamrowych, które mają znaczenie dla składni , muszą być niecytowane, elementy listy mogą nadal być cytowane indywidualnie i muszą być, jeśli zawierają globbing metaznaki, które mogą skutkować niepożądanym globowaniem po rozwinięciu nawiasów; chociaż nie jest to konieczne w tym przypadku, powyższe można zapisać jako
'--include=*.'{'html','php','htm'}

mklement0
źródło
1
Bardzo dziękuję za ten post. Świetne posty nie tylko odpowiadają na pytanie, ale uczą Cię czegoś nowego! Jest to szczególnie przydatne dla tych z nas, którzy piszą o czymś, co musi być zgodne z POSIX. Każdy, kto używa Mac OS X, powinien tu zajrzeć!
sabalaba
@sabalaba: Miło mi to słyszeć, ale żeby było jasne: chociaż rozszerzenie nawiasów klamrowych nie jest zgodne z POSIX, działa bashna każdej platformie, na której bashdziała.
mklement0
9

Spróbuj usunąć podwójne cudzysłowy

grep --include=*.{html,php,htm} pattern -R /some/path
Deruijter
źródło
@tianyapiaozi Try grep --include=\*.{html,php,htm} pattern -R /some/path. U mnie to zadziałało.
Hyunjun Kim
4

czy to nie działa?

  grep pattern  /some/path/*.{html,php,htm} 
Vijay
źródło
Nie całkiem. Pliki mogą znajdować się w podkatalogu podkatalogu
tianyapiaozi
2

Spróbuj tego. -r przeprowadzi wyszukiwanie rekurencyjne. -s pominie błędy nie znalezionych plików. -n pokaże numer wiersza pliku, w którym znajduje się wzorzec.

    grep "pattern" <path> -r -s -n --include=*.{c,cpp,C,h}
Pradeep
źródło
Jest to szczególnie dla mnie najlepsza odpowiedź i myślę, że można wstawić -rsn zamiast -r -s -n (ale to jest dziurawe).
slim
Zwykle używam -rns . Dla jasności w przykładzie musiałem wspomnieć -r -n -s :-) Cieszę się, że pomogło.
Pradeep
Polecam dodanie -Ido standardowego zestawu. Pomija pliki binarne (które prawie nigdy nie są przeszukiwane), co zwiększa wydajność. Potem idziemy grep -rIns ...co ładnie gra akustycznie :)
cholernie
2

Działa w tym samym celu, ale bez --includeopcji. Działa również na grep 2.5.1.

grep -v -E ".*\.(html|htm|php)"
Kohei Mikami
źródło
0

Używaj grepz findpoleceniem

find /some/path -name '*.html' -o -name '*.htm' -o -name '*.php' -type f 
 -exec grep PATTERN {} \+

Możesz użyć -regexi -regextypeopcji.

Książę John Wesley
źródło