Dlaczego
grep e\\.g\\. <<< "this is an e.g. wow"
i
grep e\.g\. <<< "this is an e.g. wow"
Zrobić to samo?
Jeśli dodam trzeci ukośnik, ma również ten sam wynik. ALE, kiedy dodam czwarty ukośnik, to już nie działa. Ma to związek z pytaniem ze starego egzaminu na klasę. Zapytał, czy ten z dwoma odwrotnymi ukośnikami będzie działał, aby wypisać wiersz z „np.” Początkowo myślałem, że to nie zadziała, ale próbowałem się upewnić i udało się. Jakie jest wyjaśnienie?
bash
shell
regular-expression
quoting
Wyatt Grant
źródło
źródło
\\\.
i da grep,\.
ale tak nie jest. dobre pytanieOdpowiedzi:
Po pierwsze, zwróć uwagę, że pojedynczy ukośnik pasuje zbyt wiele:
Jeśli chodzi o Basha , okres ucieczki jest taki sam jak okres. Bash przechodzi na okres grep . Dla grep kropka pasuje do wszystkiego.
Teraz rozważ:
Gdy Bash widzi podwójny ukośnik, redukuje go do pojedynczego ukośnika i przekazuje go na grep, który w pierwszym z trzech powyższych testów widzi, jak chcemy, pojedynczy ukośnik przed kropką. Tak więc robi to właściwą rzecz.
Dzięki potrójnemu ukośnikowi Bash redukuje pierwsze dwa do jednego ukośnika. Potem widzi
\.
. Ponieważ okres ucieczki nie ma specjalnego znaczenia dla Bash, jest on redukowany do zwykłego okresu. W rezultacie grep widzi, jak chcemy, cięcie przed kropką.Z czterema ukośnikami Bash redukuje każdą parę do jednego ukośnika. Bash przechodzi na grep dwa ukośniki i kropkę. grep widzi dwa ukośniki i kropkę i redukuje dwa ukośniki do jednego dosłownego ukośnika. O ile na wejściu nie ma dosłownego ukośnika, po którym następuje dowolny znak, nie ma żadnych dopasowań.
Aby zilustrować to ostatnie, pamiętaj, że w pojedynczych cudzysłowach wszystkie znaki są dosłowne. Tak więc, biorąc pod uwagę następujące trzy wiersze wejściowe, polecenie grep pasuje tylko do wiersza z literalnym ukośnikiem na wejściu:
Podsumowanie zachowania Basha
W przypadku Bash obowiązują następujące zasady
Dwa ukośniki są zredukowane do jednego ukośnika.
Cięcie przed normalnym znakiem, takim jak kropka, jest po prostu normalnym znakiem (kropka).
A zatem:
Istnieje prosty sposób na uniknięcie tego zamieszania: w wierszu poleceń Bash wyrażenia regularne należy umieszczać w cudzysłowach. Wewnątrz pojedynczych cytatów Bash pozostawia wszystko w spokoju.
źródło
echo
oświadczenie, które ilustruje, co robi bash w tych przypadkach.\.
lub.
. W przypadku bash oba są takie same: są równoważne zwykłemu okresowi. Dlatego w sumie to, co bash dostarcza grep jest takie samo dla obu: pojedynczy slash, po którym następuje kropka.echo
nie jest bardzo niezawodnym sposobem na testowanie wyrażeń regularnych z powodu wielu implementacji tego programu. Na przykład pod moim zsh (wbudowane echo)echo \. \\. \\\. \\\\. \\\\\.
daje. \. \. \. \.
, ale/bin/echo \. \\. \\\. \\\\. \\\\\.
zwraca. \. \. \\. \\.
. Coś takiegoprintf "%s" ...
jest prawdopodobnie lepszym sposobem.Dane wyjściowe są takie same tylko dla łańcucha, ale ogólnie te wyrażenia regularne robią różne rzeczy. Zmodyfikujmy trochę twój przykład, dodając drugi wzór
e,g,
(z przecinkami), trzecie\.g\.
(kropki), czwartye\,g\,
(przecinki) i-o
opcję grep, aby wydrukować tylko pasujące części.W poniższym przypadku
.
znaleziono żadnych char (zawiadomienie''
dookołae.g.
, wejdę do tego później)Następnie uciekamy
.
z ukośnikiem odwrotnym\
, więc.
dopasowany zostanie tylko literał :Ale możemy uciec
\
z innym\
, tak że dosłowność\
zostanie dopasowana, a następnie.
(tj. Dowolny znak):Ale jeśli chcemy dopasować tylko
\.
nie, potrzebujemy\,
jeszcze jednego\
, aby uniknąć specjalnego znaczenia kropki:Ponieważ nie
''
używałeś argumentu grep, musisz dodać kolejne odwrotne ukośniki, aby uniknąć odwrotnych ukośników przed interpretacją powłoki, więc:źródło
Kiedy robisz a
grep e\.g\.
, powłoka zużywa odwrotny ukośnik, więc robisz togrep e.g.
, co pasuje. Kiedy robisz agrep e\\.g\\.
, powłoka znów pochłania ukośnik, a teraz robisz togrep e\.\g.
, co znów pasuje. Teraz wygląda odwrotny ukośnik do powłoki\\
. Tak więc, gdy masz\\
, pierwszy to sekwencja ucieczki, drugi to dosłowny odwrotny ukośnik. Kiedy zrobisz agrep e\\\.g\\\.
, to wciąż kończy sięgrep e\.\g.
, ponieważ nie ma sekwencji ucieczki (\
) przed pierwszą,\
aby uczynić ją dosłowną\
. Należy pamiętać, że \ jest odwrotnym ukośnikiem, więcgrep e\\\\.\\\\g
ostatecznie jestgrep e\\.g\\.
, co oczywiście nie pasuje.Aby zobaczyć, jak powłoka widzi to, co robisz, użyj echa (np.
echo grep e\\.g\\. <<< "this is an e.g. wow"
Vs.echo grep e\\\\.g\\\\. <<< "this is an e.g. wow"
)źródło
Oba polecenia generują takie same dane wyjściowe tylko dla danych wejściowych, ale poza tym są różne. Aby zrozumieć, co się dzieje, musimy wiedzieć, w jaki sposób parametr jest interpretowany najpierw,
bash
a następnie przezgrep
.Ucieczka przed uderzeniem
\
jest znakiem specjalnym, który anuluje specjalne znaczenie następującego znaku, w tym\
samego siebie. Jeśli poniższy znak nie ma specjalnego znaczenia, jest przekazywany bez zmian. Przykłady z poleceniem i wynikiem:echo \a
:a
- zwykły znak uciekł daje postaćecho \\
:\
- Specjalny znak uciekł daje postaćecho \\\a
:\a
- kombinacja specjalna, zwykłaecho \\\\
:\\
- kombinacja specjalna, specjalnaecho
wypisze powstały ciąg pobash
interpretacji. Więcej informacji: Dokumentacja bash , hakerzy bash wiki , specyfikacji POSIX ..
nie ma specjalnego znaczenia wbash
. Jest to zwykła postać dla powłoki. Poniżej znajdują się sekwencje istotne dla twoich przykładów:echo .
:.
echo \.
:.
echo \\.
:\.
echo \\\.
:\.
echo \\\\.
:\\.
Prostsze rozwiązanie dla dosłownych ciągów znaków w bash
Aby przekazać parametry dosłownie
bash
, możesz użyć pojedynczego cudzysłowu'
. Pomiędzy pojedynczymi cudzysłowami nie musisz przejmować się specjalnym znaczeniem znaków, ponieważ pojedynczy cudzysłów jest jedynym znakiem o specjalnym znaczeniu. Możesz wstawić pojedynczy cytat po dołączeniu pierwszej części ciągu. Przykładecho 'part1'\''part2'
:part1'part2
Regex w grep
\
jest znakiem ucieczki o podobnym znaczeniu jak wbash
..
jest znakiem specjalnym, który reprezentuje pojedyncze wystąpienie dowolnego znaku . Patrz: POSIX regex , GNU grep regex . Przykłady wyrażeń regularnych:.
- pasuje do dowolnej postaci, takiej jaka
lub.
\.
- pasuje tylko.
dosłownieTwoje przykłady
W drugiej linii każdego przykładu poniżej znajdziesz równoznaczne z apostrofami
'
pokazano ciągiem znaków, który jest przekazywany przezbash
sięgrep
. Następnie pogrep
wykonaniu zmiany jedynym możliwym znakiem specjalnym w przykładach jest.
dopasowanie dowolnego znaku. W trzecim wierszu znajduje się opis pasujący do wyrażenia.grep e.g. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
dowolny znakg
dowolny znak - dopasowaniae.g.
i ewentualnie inne ciągi, takie jakeagb
grep e\.g\. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
dowolny znakg
dowolny znak - dopasowaniae.g.
i ewentualnie inne ciągi, takie jakexgy
grep e\\.g\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
dosłownie - tylko dopasowaniae.g.
grep e\\\.g\\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
dosłownie - tylko dopasowaniae.g.
grep e\\\\.g\\\\. <<< "this is an e.g. wow"
grep 'e\\.g\\.' <<< "this is an e.g. wow"
e\
dowolna postaćg\
dowolna postać - nie pasujee.g.
źródło