Jak mogę grepować za to lub tamto (2 rzeczy) w pliku?

37

Mam plik, który ma „wtedy” i „tam”.

mogę

$ grep "then " x.x
x and then some
x and then some
x and then some
x and then some

i ja mogę

$ grep "there " x.x
If there is no blob none some will be created

Jak mogę wyszukać oba w jednej operacji? próbowałem

$ grep (then|there) x.x

-bash: błąd składni w pobliżu nieoczekiwanego tokena `('

i

grep "(then|there)" x.x
durrantm.../code
# (Nothing)
Michael Durrant
źródło

Odpowiedzi:

53

Musisz umieścić wyrażenie w cudzysłowie. Błąd, który otrzymujesz, jest wynikiem interpretacji bash (jako znaku specjalnego.

Musisz także powiedzieć grepowi, aby używał rozszerzonych wyrażeń regularnych.

$ grep -E '(then|there)' x.x

Bez rozszerzonych wyrażeń regularnych, trzeba uciec |, (i ). Pamiętaj, że używamy tutaj pojedynczych cudzysłowów. Bash specjalnie traktuje ukośniki odwrotne w obrębie podwójnych cudzysłowów.

$ grep '\(then\|there\)' x.x

W tym przypadku grupowanie nie jest konieczne.

$ grep 'then\|there' x.x

Byłoby to konieczne dla czegoś takiego:

$ grep 'the\(n\|re\)' x.x

źródło
3
Zobacz także grep $'then\nthere'i grep -e then -e there. Pamiętaj, że \|nie jest to standardem w BRE. Reszta to. Bash traktuje backslashe specjalnie w cudzysłowach tylko przed ", $, \ , `i nowej linii.
Stéphane Chazelas
1
Jaki jest cel x.x?
alex
7

To tylko szybki dodatek, większość smaków ma polecenie o nazwie egrep, które jest po prostu grep z -E. Osobiście lubię pisać dużo lepiej

egrep "i(Pod|Pad|Phone)" access.log

Niż użyć grep -E

Trausti Thor
źródło
2

Rzeczy udokumentowane w REGULARNE WYRAŻENIA na (lub przynajmniej mojej) stronie podręcznika są w rzeczywistości dla rozszerzonych wyrażeń regularnych;

grep rozumie trzy różne wersje składni wyrażeń regularnych: „podstawowe”, „rozszerzone” i „perl”. W GNU grep nie ma różnicy w dostępnej funkcjonalności między podstawowymi i rozszerzonymi składniami. W innych implementacjach podstawowe wyrażenia regularne są mniej wydajne. Poniższy opis dotyczy rozszerzonych wyrażeń regularnych; różnice dla podstawowych wyrażeń regularnych są następnie podsumowane.

Ale grep domyślnie ich nie używa - potrzebujesz -Eprzełącznika:

grep "(then|there)" x.x

Ponieważ (ponownie ze strony man):

Podstawowe i rozszerzone wyrażenia regularne

W podstawowych wyrażeniach regularnych metaznaki?, +, {, |, (I) tracą swoje specjalne znaczenie; zamiast tego użyj wersji z odwrotnymi ukośnikami \ ?, +, {, \ |, (i).

Możesz więc użyć również:

grep "then\|there" x.x

Ponieważ w tym przypadku nawiasy są zbędne.

Złotowłosa
źródło
0

Wygląda na to, że elegancka prostota Basha gubi się na ogromnej stronie podręcznika.

Oprócz powyższych doskonałych rozwiązań, pomyślałem, że postaram się przedstawić wam ściągę na temat tego, jak bash analizuje i interpretuje wypowiedzi . Następnie, korzystając z tego przewodnika, przeanalizuję przykłady przedstawione przez pytającego, aby lepiej zrozumieć, dlaczego nie działają one zgodnie z przeznaczeniem.


Uwaga: Wiersze skryptu powłoki są używane bezpośrednio. Wpisane wiersze wprowadzania są najpierw rozszerzane w historii.

Każda linia uderzenia jest najpierw tokenizowana , czyli innymi słowy pocięta na tak zwane tokeny . (Tokenizacja występuje przed wszystkimi innymi rozszerzeniami, w tym nawiasami klamrowymi, tyldą, parametrem, poleceniem, arytmetyką, procesem, dzieleniem słów i rozwijaniem nazw plików).

Token tutaj oznacza część linii wejściowej oddzieloną (oddzieloną) jednym z tych specjalnych metaznaków:

space,  - White space...
tab, 
newline,

‘<’,    - Redirection & piping...
‘|’, 
‘>’
‘&’,    - And/Both < | > | >>  .or.  &<file descriptor>

‘;’,    - Command termination

‘(’,    - Subshell, closed by -     ‘)’

Bash używa wielu innych znaków specjalnych, ale tylko te 10 produkuje początkowe żetony.

Ponieważ jednak te metaznaki również muszą być czasami używane w ramach tokena, musi istnieć sposób na usunięcie ich specjalnego znaczenia. To się nazywa ucieczka. Uciekając odbywa się albo poprzez cytowanie ciąg jednego lub więcej znaków (np 'xx..', "xx..") lub poprzedzając indywidualny charakter z back-slash (tj \x). (Jest to trochę bardziej skomplikowane niż to, ponieważ cytaty również muszą być cytowane, a ponieważ podwójne cudzysłowy nie cytują wszystkiego, ale na razie wystarczy to uproszczenie).

Nie myl cytowania bash z pomysłem cytowania ciągu tekstu, jak w innych językach. Pomiędzy cudzysłowami w bash nie są ciągi, lecz sekcje wiersza wejściowego, w których metaznaki są znakami ucieczki, aby nie ograniczały tokenów.

Zauważ, że istnieje ważna różnica między ', a ", ale to na inny dzień.

Pozostałe nieskalowane metaznaki stają się następnie separatorami tokenów.

Na przykład,

$ echo "x"'y'\g
xyg

$ echo "<"'|'\>
<|>

$ echo x\; echo y
x; echo y

W pierwszym przykładzie są dwa tokeny wyprodukowane przez separator spacji: echoi xyz.

Podobnie w drugim przykładzie.

W trzecim przykładzie średnik jest uciekł, więc istnieją 4 żetony produkowane przez separator przestrzeni, echo, x;, echo, i y. Pierwszy token jest następnie uruchamiany jako polecenie i przyjmuje kolejne trzy tokeny jako dane wejściowe. Uwaga: 2. miejsce echonie jest wykonywane.


Ważną rzeczą do zapamiętania jest to, że bash najpierw szuka uciekających znaków ( ', "i \), a następnie szuka nieskalowanych ograniczników meta-znaków, w tej kolejności.

Jeśli nie uciekł, te 10 znaków specjalnych służy jako tokenograniczniki. Niektóre z nich mają również dodatkowe znaczenie, ale przede wszystkim są ogranicznikami tokenów.


Czego oczekuje grep

W powyższym przykładzie grep potrzebuje tych tokenów grep, string, filename.

Pierwsza próba pytania brzmiała:

$ grep (potem | tam) xx

W tym przypadku (, )i |to bez zmiany znaczenia znaków meta i tak służyć do podziału wkładu w te tokeny: grep, (, then, |, there, ), i x.x. grep chce zobaczyć grep, then|therei x.x.

Drugą próbą pytania było:

grep "(następnie | tam)" xx

Ten tokenizes w grep, (then|there), x.x. Możesz to zobaczyć, jeśli zamienisz grep na echo:

echo "(następnie | tam)" xx
(następnie | tam) xx

Widok eliptyczny
źródło