Chcę znaleźć wszystkie wiersze w kilku plikach, które pasują do jednego z dwóch wzorów. Próbowałem znaleźć wzorce, których szukam, pisząc
grep (foo|bar) *.txt
ale powłoka interpretuje |
potok i narzeka, gdy bar
nie jest plikiem wykonywalnym.
Jak mogę grep dla wielu wzorców w tym samym zestawie plików?
Odpowiedzi:
Najpierw musisz chronić wzór przed rozszerzeniem przez powłokę. Najłatwiej to zrobić, umieszczając wokół niego pojedyncze cudzysłowy. Pojedyncze cudzysłowy zapobiegają rozszerzaniu czegokolwiek między nimi (w tym ukośników odwrotnych); jedyne, czego nie możesz zrobić, to mieć pojedyncze cudzysłowy we wzorze.
Jeśli potrzebujesz pojedynczego cytatu, możesz zapisać go jako
'\''
(literał końca łańcucha, cytat literału, literał ciągu otwartego).Po drugie, grep obsługuje dwie składnie wzorców. Stara, domyślna składnia ( podstawowe wyrażenia regularne ) nie obsługuje
|
operatora alternation ( ), chociaż niektóre wersje mają go jako rozszerzenie, ale napisane odwrotnym ukośnikiem.Przenośnym sposobem jest użycie nowszej składni, rozszerzonych wyrażeń regularnych . Musisz przekazać
-E
opcję, abygrep
ją wybrać. W Linuksie możesz także pisaćegrep
zamiastgrep -E
(w innych jednorożcach możesz zrobić z tego alias).Inną możliwością, gdy szukasz tylko jednego z kilku wzorców (w przeciwieństwie do budowania złożonego wzorca przy użyciu rozłączenia), jest przekazanie wielu wzorców do
grep
. Możesz to zrobić, poprzedzając każdy wzór-e
opcją.źródło
fgrep
lubgrep -F
, w przypadku małych wzorów różnica będzie znikoma, ale wraz z upływem czasu korzyści zaczną się pokazywać ...grep -F
rzeczywista poprawa wydajności zależy od implementacji grep: niektóre z nich i tak stosują ten sam algorytm, więc-F
ma to wpływ tylko na czas analizowania wzorca, a nie na wyszukiwanie czasu. Na przykład GNU grep nie jest szybszy-F
(ma również błąd, którygrep -F
spowalnia w lokalizacjach wielobajtowych - ten sam stały wzorzecgrep
jest w rzeczywistości znacznie szybszy!). Z drugiej strony, BusyBox grep bardzo zyskuje-F
na dużych plikach.egrep
poprzedzagrep -E
. Nie jest on specyficzny dla GNU (z pewnością nie ma nic wspólnego z Linuksem). W rzeczywistości nadal znajdziesz systemy takie jak Solaris, w których domyślnagrep
nadal nie obsługuje-E
.lub
wybiórczo powołując się na stronę man gnu-grep:
(...)
Na początku nie czytałem dalej, więc nie rozpoznałem subtelnych różnic:
Zawsze używałem egrep i niepotrzebnie parens, ponieważ uczyłem się na przykładach. Teraz nauczyłem się czegoś nowego. :)
źródło
Jak powiedział TC1,
-F
wydaje się użyteczną opcją:źródło
Po pierwsze, musisz używać cudzysłowów dla znaków specjalnych. Po drugie, mimo to
grep
nie zrozumie bezpośrednio alternacji; musisz użyćegrep
lub (grep
tylko z GNU )grep -E
.(Nawiasy są niepotrzebne, chyba że alternacja jest częścią większego wyrażenia regularnego.)
źródło
grep -E
jest bardziej standardowy niżegrep
.Jeśli nie potrzebujesz wyrażeń regularnych, jest to znacznie szybsze w użyciu
fgrep
lubgrep -F
z wieloma parametrami -e, takimi jak:fgrep
(alternatywniegrep -F
) jest znacznie szybszy niż regularne grep, ponieważ szuka stałych ciągów zamiast wyrażeń regularnych.źródło
fgrep
są przestarzałe.Możesz wypróbować poniższe polecenie, aby uzyskać wynik:
źródło
Tani i wesoły sposób na grep dla wielu wzorów:
źródło
-f
opcja grep pobiera plik z wieloma wzorami. Zamiast tworzyć plik tymczasowy (który możesz później zapomnieć usunąć), po prostu użyj podstawienia procesu powłoki:grep -f <(echo foo; echo bar) *.txt
Pipe (
|
) jest specjalnym znakiem powłoki, więc albo należy go zmienić (\|
), albo cytować zgodnie z instrukcją (man bash
):Zobacz: Które postacie należy uciec w Bash?
Oto kilka przykładów (użycie niewymienionych jeszcze narzędzi):
Używanie
ripgrep
:rg "foo|bar" *.txt
rg -e foo -e bar *.txt
Używanie
git grep
:git grep --no-index -e foo --or -e bar
Uwaga: Wspiera on także wyrażeń logicznych takich jak
--and
,--or
i--not
.Aby dowiedzieć się więcej o operacji AND na wiersz, zobacz: Jak uruchomić grep z wieloma wzorcami AND?
Aby dowiedzieć się więcej o operacji AND na plik, zobacz: Jak sprawdzić wszystkie ciągi znaków lub wyrażenia regularne w pliku?
źródło
Miałem dzienniki dostępu, w których daty były głupio sformatowane: [30 / Jun / 2013: 08: 00: 45 +0200]
Ale musiałem wyświetlić go jako: 30 / Jun / 2013 08:00:45
Problem polega na tym, że używając „OR” w mojej instrukcji grep, otrzymywałem dwa wyrażenia dopasowania w dwóch osobnych wierszach.
Oto rozwiązanie:
źródło
TL; DR: jeśli chcesz zrobić więcej rzeczy po dopasowaniu jednego z wielu wzorców, dołącz je jak w
\(pattern1\|pattern2\)
przykład: chcę znaleźć wszystkie miejsca, w których zmienna zawierająca nazwę „data” jest zdefiniowana jako String lub int. (np. „int cronDate =” lub „String textFormattedDateStamp =”):
Dzięki
grep -E
nie musisz uciec od nawiasów ani potoku, tzn.grep -E '(int|String) [a-zA-Z_]*date[a-zA-Z_]* ='
źródło
To działa dla mnie
źródło
Można to zrobić na wiele sposobów.
grep 'foo\|bar' *.txt
egrep 'foo|bar' *.txt
find . -maxdepth 1 -type f -name "*.txt" | xargs grep 'foo\|bar'
find . -maxdepth 1 -type f -name "*.txt" | xargs egrep 'foo|bar'
Trzecia i czwarta opcja będzie grepować tylko w plikach i unikać katalogów posiadających
.txt
ich nazwy.Tak więc, zgodnie z twoim przypadkiem użycia, możesz użyć dowolnej z wyżej wymienionych opcji.
Dzięki!!
źródło
aby dodać do odpowiedzi @ geekozaura , jeśli masz wiele wzorów zawierających tabulatory i spację, użyj następującego polecenia
gdzie
[[:blank:]]
jest klasą RE, która reprezentuje spację lub znak tabulacjiźródło