Używam GNU bash
4.3.48
. Rozważ następujące dwa polecenia, które różnią się tylko jednym znakiem dolara.
Polecenie 1:
echo "(echo " * ")"
Polecenie 2:
echo "$(echo " * ")"
Ich wyniki są odpowiednio
(echo test.txt ppcg.sh )
i
*
Więc oczywiście w pierwszym przypadku *
jest on globowany, co oznacza, że pierwszy znak cudzysłowu idzie z drugim, tworząc parę, a trzeci i czwarty tworzą inną parę.
W drugim przypadku *
znak nie jest globowany, a na wyjściu są dokładnie dwie dodatkowe spacje, jedna przed gwiazdką, a druga po niej, co oznacza, że drugi znak cudzysłowu jest zgodny z trzecim, a pierwszy z czwartym.
Czy istnieją inne przypadki poza $()
konstrukcją, że znaki cudzysłowu nie są dopasowane do następnego, ale są zagnieżdżone? Czy to zachowanie jest dobrze udokumentowane, a jeśli tak, to gdzie mogę znaleźć odpowiedni dokument?
Odpowiedzi:
Każda z konstrukcji zagnieżdżonych, które mogą być interpolowane wewnątrz łańcuchów, może zawierać w sobie dalsze łańcuchy: są one przetwarzane jak nowy skrypt, aż do znacznika zamykającego, a nawet mogą być zagnieżdżone na wielu poziomach głębokości. Wszystkie takty jednego z nich zaczyna się od
$
. Wszystkie są udokumentowane w połączeniu instrukcji Bash i specyfikacji języka poleceń powłoki POSIX.Istnieje kilka przypadków tych konstrukcji:
Zastąpienie poleceń
$( ... )
, jak już znalazłeś. POSIX określa to zachowanie :Cytaty są częścią prawidłowych skryptów powłoki, więc są dozwolone w ich normalnym znaczeniu.
`
również.Element „word” zaawansowanych instancji podstawiania parametrów, takich jak
${parameter:-word}
. Definicja „słowo” jest :- który zawiera cytowany tekst, a nawet mieszane cytaty
a"b"c'd'e
- chociaż rzeczywiste zachowanie rozszerzeń jest nieco bardziej liberalne i na przykład${x:-hello world}
działa również.Rozwinięcie arytmetyczne z
$(( ... ))
, chociaż tam jest w dużej mierze bezużyteczne (ale można zagnieżdżać podstawianie poleceń lub rozszerzenia zmiennych, a następnie użyteczne w nich cudzysłowy). POSIX stwierdza, że :więc to zachowanie jest wyraźnie wymagane. Oznacza to
echo "abc $((4 "*" 5))"
raczej arytmetykę niż globowanie.Zauważ jednak, że interpretacja
$[ ... ]
arytmetyczna w starym stylu nie jest traktowana w ten sam sposób: cudzysłowy będą błędem, jeśli się pojawią, niezależnie od tego, czy rozwinięcie jest cytowane, czy nie. Ten formularz nie jest już w ogóle dokumentowany i i tak nie jest przeznaczony do użycia.$"..."
, które faktycznie używa"
jako podstawowego elementu.$"
jest traktowany jako jedna jednostka.Jest jeszcze jeden przypadek zagnieżdżenia, którego można się nie spodziewać, nie obejmujący cudzysłowów, który dotyczy rozszerzenia nawiasów :
{a,b{c,d},e}
rozwija się do „a bc bd e”.${x:-a{b,c}d}
robi nie gniazdo, jednak; jest traktowane jako podstawienie parametru, podając „a{b,c
”, a następnie „d}
”. Jest to również udokumentowane :Zasadniczo wszystkie konstrukcje rozdzielane parsują swoje ciała niezależnie od otaczającego kontekstu (i wyjątki są traktowane jak błędy ). Zasadniczo po zobaczeniu
$(
kodu zastępującego polecenie prosi analizator składni, aby zużył tyle, ile może z ciała, jakby to był nowy program, a następnie sprawdza, czy oczekiwany znacznik kończący (nieskalowany)
lub))
lub}
) pojawia się po uruchomieniu podparsera z rzeczy, które może konsumować.Jeśli myślisz o działaniu parsera rekurencyjno-opadającego , jest to zwykła rekurencja do przypadku podstawowego. W rzeczywistości jest to łatwiejsze niż w inny sposób, gdy w ogóle masz interpolację łańcuchów. Bez względu na podstawową technikę analizowania, powłoki obsługujące te konstrukty dają ten sam wynik.
Możesz zagnieżdżać cytaty tak głęboko, jak chcesz w tych konstrukcjach i będzie działać zgodnie z oczekiwaniami. Nigdzie nie pomylić, widząc cytat na środku; zamiast tego będzie to początek nowego cytowanego ciągu w kontekście wewnętrznym.
źródło
"blah/blah\n$(cat "${tmpdir}/${filename}.jpdf")"
: dlaczego drugi podwójny cudzysłów nie jest końcem pierwszego podwójnego cudzysłowu (jak pokazuje składnia podświetlenia w odpowiedzi), ale jest początkiem łańcucha$(...)
? Czy to dlatego, że parser bash jest odgórny, a nie oddolny?"${var-"foo"}"
(echo "${-+"*"}"
na przykład takich samych jakecho *
w powłoce Bourne'a lub Korna), a zachowanie zostanie wyraźnie określone w następnej wersji standardu . Zobacz także dyskusję na mail-archive.com/[email protected]/msg00167.htmlByć może spojrzenie na dwa przykłady z
printf
(zamiastecho
) pomoże:Drukuje
(echo
(pierwsze słowo, w tym spację końcową), niektóre pliki i słowo zamykające)
.Nawias jest tylko częścią cytowanego ciągu
(echo
.Gwiazdka (teraz niecytowana, ponieważ dwa podwójne cudzysłowy są sparowane) jest rozszerzana jako glob do listy pasujących plików.
A potem nawias zamykający.
Jednak drugie polecenie działa w następujący sposób:
$
Rozpoczyna podstawienia komendy. To zaczyna od nowa cytat.Gwiazdka jest cytowana
" * "
i to właśnie wydaje polecenie (tutaj jest to polecenie, a nie ciąg cytowany)echo
. Na koniecprintf
ponownie sformatuj*
i wydrukuje go jako< * >
.źródło