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: echo
i 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 echo
nie 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 token
ograniczniki. 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|there
i 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