StackOverflow odpowiedź z> 3.5K głosów dysponuje ten jeden-liner przypisywania do DIR
katalogu bieżącego skryptu bash:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
Zaskakują mnie zagnieżdżone podwójne cudzysłowy. O ile wiem, następujące fragmenty są cytowane:
"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"
... i wszystko inne po prawej stronie =
(tj. $( dirname
i )
) jest nie cytowane. Innymi słowy, zakładam, że 2., 4. i 6. "
znak „zamykają” odpowiednio 1., 3. i 5. "
znak.
Rozumiem, co "${BASH_SOURCE[0]}"
osiągają podwójne cudzysłowy , ale jaki jest cel pozostałych dwóch par podwójnych cudzysłowów?
Jeśli natomiast (pomimo wysokiego wyniku głosowania) powyższy fragment kodu jest niepoprawny, jaki jest właściwy sposób osiągnięcia jego zamierzonego celu?
(Przez nominalne zamiary mam na myśli: zbierz wartość zwróconą pwd
po pierwszym cd
uruchomieniu do katalogu zwróconego przez dirname "${BASH_SOURCE[0]}"
i wykonaj cd
-ing w podpowłoce, aby $PWD
powłoka nadrzędna pozostała niezmieniona).
$( here, it's a subshell, but you are writing code as if you were writing it on the "first level" of the shell .... )
.lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
działa również.Odpowiedzi:
Twoja łamigłówka nie zgadza się z tym, jak
bash
(i ogólnie powłoka) przeanalizowała dane wejściowe. W:Najpierw
bash
przeanalizuj prawą stronę przypisania do jednego długiego łańcucha,$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
ponieważ w cudzysłowie mogą pojawić się podwójne cudzysłowy .Następnie
bash
zacznij analizować podstawienie polecenia. Ponieważ wszystkie znaki następujące po otwartym nawiasie do otaczającego nawiasu są używane do konstruowania polecenia w ramach podstawiania poleceń, otrzymasz:Powłoka kontynuuje parsowanie tego złożonego polecenia, podziel go na dwie części:
cd "$( dirname "${BASH_SOURCE[0]}" )"
Następnie zastosuj tę samą regułę analizy
cd "$( dirname "${BASH_SOURCE[0]}" )"
, ale tym razem podwójne cudzysłowy nie są zbędne, ale mają sens. Zapobiegają podziałowi pola na wynik$( dirname "${BASH_SOURCE[0]}" )
, a także na rozszerzenie${BASH_SOURCE[0]}
(w przeciwieństwie do najbardziej podwójnych cudzysłowów zewnętrznych, nie będą konieczne w RHS o zmiennym przypisaniu, aby zapobiecsplit+glob
).Ta reguła dotyczy zastępowania poleceń we wszystkich powłokach POSIX . Więcej szczegółów puzzli można przeczytać w sekcji Rozpoznawanie tokenów specyfikacji POSIX .
źródło
Gdy ktoś jest w środku
$(...)
, cytowanie zaczyna się od nowa.Innymi słowy,
"..."
i$(...)
mogą się zagnieżdżać w sobie. Podstawienie procesu$(...)
, może zawierać jeden lub więcej kompletnych ciągów cudzysłowów. Również ciągi cudzysłowowe mogą zawierać jedno lub więcej kompletnych podstawień procesu. Ale nie przeplatają się. Zatem ciąg cudzysłowu, który zaczyna się w podstawieniu procesu, nigdy nie wyjdzie poza niego ani na odwrót.Zastanów się:
Wewnątrz
$(...)
jest:Powyżej
${BASH_SOURCE[0]}
jest podwójnie cytowany. Wszelkie cudzysłowy, podwójne lub pojedyncze, poza nimi$(...)
są nieistotne przy ustalaniu, że${BASH_SOURCE[0]}
są cytowane.Zewnętrzna
$(...)
zawiera:Tutaj wyrażenie
$( dirname "${BASH_SOURCE[0]}" )
jest cytowane podwójnie. Fakt, że istnieją cudzysłowy poza zewnętrznym, nie$(...)
ma znaczenia przy rozważaniu tego, co jest w nim. Fakt, że w środku są cytaty,$(...)
również nie ma znaczenia.Oto jak pasują podwójne cudzysłowy:
źródło
irrelevant
? Z wyjątkiem większości nawiasów zewnętrznych wszystkie pozostałe mają swoje znaczenie.$(...)
wiąże się mocniej niż"..."
” nie ma sensu. Nie są operatorami poprawkowymi i nie ma między nimi hierarchii (gdyby tak było, oznaczałoby to, że albo cudzysłowy nie mogą znajdować się w nawiasach, albo nawiasy nie mogą być wewnątrz cudzysłowów, ale tak nie jest). Termin techniczny to taki$(…)
i"…"
gniazdo.