zagnieżdżone podwójne cudzysłowy w wysoko ocenianym jednym wierszu


20

StackOverflow odpowiedź z> 3.5K głosów dysponuje ten jeden-liner przypisywania do DIRkatalogu 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. $( dirnamei )) 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ą pwdpo pierwszym cduruchomieniu do katalogu zwróconego przez dirname "${BASH_SOURCE[0]}"i wykonaj cd-ing w podpowłoce, aby $PWDpowłoka nadrzędna pozostała niezmieniona).


1
to ze względu na cechę $ (...) $( here, it's a subshell, but you are writing code as if you were writing it on the "first level" of the shell .... ).
Olivier Dulac

Przybyłem tutaj z powodu skryptu instalacyjnego dokera. Aby znaleźć nazwę dystrybucji:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
David Tonhofer,

Pamiętaj, że spacje w linii nie są potrzebne: DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"działa również.
David Tonhofer,

Odpowiedzi:


12

Twoja łamigłówka nie zgadza się z tym, jak bash(i ogólnie powłoka) przeanalizowała dane wejściowe. W:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Najpierw bashprzeanalizuj 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 bashzacznij 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:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

Powłoka kontynuuje parsowanie tego złożonego polecenia, podziel go na dwie części:

  • cd "$( dirname "${BASH_SOURCE[0]}" )"
  • pwd

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 .


21

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ę:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Wewnątrz $(...)jest:

dirname "${BASH_SOURCE[0]}"

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:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

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:

wprowadź opis zdjęcia tutaj


Co masz na myśli irrelevant? Z wyjątkiem większości nawiasów zewnętrznych wszystkie pozostałe mają swoje znaczenie.
cuonglm

4
I dlatego nie powinieneś używać backticksa: reguły cytowania są bardzo dziwne i nieintuicyjne.
Wildcard

Zdanie „ $(...)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.
Gilles „SO- przestań być zły”

@Gilles Bardzo dobrze. Właśnie zmieniłem zdanie, mając nadzieję na lepsze uchwycenie koncepcji.
John1024
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.