verschachtelte doppelte Anführungszeichen in hoch bewerteten Einzeiler

20

Eine StackOverflow- Antwort mit> 3.5K Stimmen enthält diesen Einzeiler für die Zuordnung zum DIRVerzeichnis des aktuellen Bash-Skripts:

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

Ich bin verwirrt über die geschachtelten Anführungszeichen. Soweit ich das beurteilen kann, werden folgende Fragmente in doppelte Anführungszeichen gesetzt:

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

... und alles andere rechts vom =(dh $( dirnameund )) ist nicht zitiert. Mit anderen Worten, ich gehe davon aus, dass das 2., 4. und 6. "Zeichen das 1., 3. bzw. 5. "Zeichen "schließt" .

Ich verstehe, was die doppelten Anführungszeichen "${BASH_SOURCE[0]}"bewirken, aber wozu dienen die beiden anderen doppelten Anführungszeichen?

Wenn andererseits (und trotz der hohen Stimmenzahl) das obige Snippet falsch ist, wie kann man dann seine nominelle Absicht erreichen?

(Mit nominaler Absicht meine ich: sammeln Sie den Wert, der von zurückgegeben wurde, pwdnachdem Sie zuerst cdin das Verzeichnis von zurückgegeben haben dirname "${BASH_SOURCE[0]}", und führen Sie das cd-ing in einer Sub-Shell aus, so dass der Wert $PWDder übergeordneten Shell unverändert bleibt.)

kjo
quelle
1
es ist aufgrund eines Features von $ (...): $( 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
Ich bin wegen des Docker-Installationsskripts hierher gekommen. So finden Sie den Namen der Distribution:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
David Tonhofer
Beachten Sie, dass Leerzeichen in der Zeile nicht benötigt werden: DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"funktioniert auch.
David Tonhofer

Antworten:

12

Ihr Rätsel ist nicht richtig, wie bash(und die Shell im Allgemeinen) die Eingabe analysiert hat. Im:

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

Zuerst bashanalysiert , um die rechte Seite Zuordnung zu einer langen Reihe , $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )weil doppelte Anführungszeichen innerhalb erscheinen doppelte Anführungszeichen .

bashBeginnen Sie danach mit dem Parsen der Befehlsersetzung. Da alle Zeichen, die offenen Klammern bis hin zu eingeschlossenen Klammern folgen, zum Erstellen des Befehls innerhalb der Befehlsersetzung verwendet werden, erhalten Sie:

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

Die Shell analysiert diesen zusammengesetzten Befehl weiter und teilt ihn in zwei Teile:

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

Wenden Sie dann dieselbe Parsing-Regel für an cd "$( dirname "${BASH_SOURCE[0]}" )", aber dieses Mal sind doppelte Anführungszeichen nicht redundant, aber sinnvoll. Sie verhindern eine Feldaufteilung auf Ergebnis $( dirname "${BASH_SOURCE[0]}" )und auch die Erweiterung von ${BASH_SOURCE[0]}(im Gegensatz zu den äußersten doppelten Anführungszeichen ist es in RHS nicht erforderlich, eine variable Zuordnung zu verhindernsplit+glob ).


Diese Regel gilt für die Befehlsersetzung in allen POSIX-Shell . Ein detaillierteres Puzzle können Sie im Abschnitt "Token Recognition" der POSIX-Spezifikation lesen .

cuonglm
quelle
21

Sobald man drinnen ist $(...), fängt das Zitieren von vorne an.

Mit anderen Worten, "..."und $(...)können ineinander verschachteln . Die Prozessersetzung $(...)kann eine oder mehrere vollständige Zeichenfolgen in doppelten Anführungszeichen enthalten. Doppelte Anführungszeichenfolgen können auch eine oder mehrere vollständige Prozessersetzungen enthalten. Sie greifen jedoch nicht ineinander. Eine Zeichenfolge in doppelten Anführungszeichen, die innerhalb einer Prozessersetzung beginnt, wird sich daher niemals außerhalb der Zeichenfolge erstrecken oder umgekehrt.

Also, bedenken Sie:

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

Im Inneren $(...)ist:

dirname "${BASH_SOURCE[0]}"

Oben ${BASH_SOURCE[0]}steht doppelt in Anführungszeichen. Alle doppelten oder einfachen Anführungszeichen außerhalb von $(...)sind irrelevant, wenn festgestellt wird, dass ${BASH_SOURCE[0]}doppelte Anführungszeichen verwendet werden.

Das Äußere $(...)enthält:

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

Hier wird der Ausdruck $( dirname "${BASH_SOURCE[0]}" )in doppelte Anführungszeichen gesetzt. Die Tatsache, dass es Anführungszeichen außerhalb des Äußeren gibt, $(...)ist irrelevant, wenn man bedenkt, was darin enthalten ist. Die Tatsache, dass es im Inneren Anführungszeichen $(...)gibt, spielt ebenfalls keine Rolle.

So stimmen die doppelten Anführungszeichen überein:

Bildbeschreibung hier eingeben

John1024
quelle
Was meinen Sie irrelevant? Mit Ausnahme der äußersten Klammern haben alle anderen eine eigene Bedeutung.
Donnerstag,
4
Und aus diesem Grund sollten Sie keine Backticks verwenden: Die Regeln für das Zitieren sind äußerst seltsam und nicht intuitiv.
Wildcard
Der Satz " $(...)bindet enger als "..."" ergibt keinen Sinn. Sie sind keine Infix-Operatoren und es gibt keine Hierarchie zwischen ihnen (wenn dies der Fall wäre, würde dies bedeuten, dass entweder Anführungszeichen nicht in Klammern oder Klammern nicht in Anführungszeichen stehen können, aber das ist nicht der Fall). Der Fachbegriff ist das $(…)und "…"Nest.
Gilles 'SO- hör auf böse zu sein'
@ Gilles Sehr gut. Ich habe es nur in der Hoffnung umformuliert, das Konzept besser einfangen zu können.
John1024