Variable in Bash, die Befehlsersetzung enthält

Variable in Bash, die Befehlsersetzung enthält

Ich versuche, Shell-Erweiterungen in Bash zu verstehen (GNU Bash, Version 4.4.20(1)-Release (i686-PC-Linux-Gnu)).

Tippen in meiner interaktiven Bash-Shell

x='$(id)'
$x
$(echo $x)

Ich erwartete von jeder der letzten 2 Zeilen einen Fehler der Form

bash: uid=xxx(user): command not found

aber bekam

bash: $(id): command not found.

Ich verstehe nicht, warum hier keine Befehlssubstitution stattfindet. Sollte dies nicht nach der Variablenerweiterung erfolgen? Ich vermute, dass es mit Shell-Operationen zu tun hat, wie hier beschriebenhttps://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Operation

Kann jemand dieses Verhalten erklären?

Ich bin nur daran interessiert, Bash-Erweiterungen genauer zu verstehen. Ich bin in meiner Frage nicht daran interessiert, ein tatsächliches Skript auszuführen.

Antwort1

$(…)ist eine Befehlssubstitution („Prozesssubstitution“ ist <(…)und dergleichen). Variablensubstitutionen und Befehlssubstitutionen erfolgen im selben Durchgang, von links nach rechts in der Zeichenfolge. Die einzigen Dinge, die im Ergebnis dieser Substitutionen auftreten, sind Worttrennung und Globbing.

x='$(id)'Setzt also xauf die 5-stellige Zeichenfolge $(id). Um dann auszuführen $x, ersetzt die Shell $xdurch den Wert $(id). Dieser enthält keine Leerzeichen oder Glob-Zeichen und wird daher als Befehlsname behandelt.

Vergleich mit:

x='@(id)'
shopt -s extglob
echo /none/$x /usr/bin/$x

Unter der Annahme, dass die Datei /none/idnicht existiert /usr/bin/id, wird der echoBefehl jedoch auf drei Wörter erweitert: echo(offensichtlich), /none/@(id)(das Glob-Muster /none/@(id)stimmt mit nichts überein und bleibt daher unverändert) und /usr/bin/id(das Glob-Muster /usr/bin/@(id)stimmt mit einer Datei überein und wird daher durch die einelementige Liste der Übereinstimmungen ersetzt).

Im Bash-Handbuch steht der entsprechende Satz am Anfang derShell-ErweiterungenAbschnitt.

Die Reihenfolge der Erweiterungen ist: Klammernerweiterung, Tilde-Erweiterung, Parameter- und Variablenerweiterung, arithmetische Erweiterung und Befehlsersetzung (von links nach rechts), Worttrennung und Dateinamenerweiterung.

Alles zwischen zwei Semikolons ist ein Durchgang. Jeder Durchgang arbeitet mit dem Ergebnis des vorherigen Durchgangs.

Beachten Sie, dass ein einzelner Satz (selbst ein komplexer wie der oben zitierte) nicht die ganze Geschichte erzählen kann. Die Shell-Semantik ist verworren. Ich bezweifle, dass in einem Shell-Handbuch alle Einzelheiten zu den Sonderfällen aufgeführt sind.POSIX-Spezifikationist formeller, deckt aber keine Bash-spezifischen Erweiterungen ab und lässt sogar einige wirklich seltsame Fälle undefiniert.

Antwort2

Es geht um die Anführungszeichen. Einfache Anführungszeichen ( ') definieren eine wörtliche Zeichenfolge und es kann keine Interpolation oder Escape-Zeichen vorkommen. Doppelte Anführungszeichen ( ") ermöglichen sowohl Interpolation als auch Escape-Zeichen.

Hier ist ein Beispiel:

$ x='$(id)'
$ echo 'The variable x contains the value \"$x\"'
The variable x contains the value \"$x\"
$ echo "The variable x contains the value \"$x\""
The variable x contains the value "$(id)"

$ x="$(id)"
$ echo "The variable x contains the value \"$x\""
The variable x contains the value "uid=1000(myusername)..."

Hier ist ein weiteres Beispiel für Interpolation und Escape basierend auf einfachen bzw. doppelten Anführungszeichen:

$ echo 'The current directory is $PWD according to the variable \"\$PWD\".'
The current directory is $PWD according to the variable \"\$PWD\".

$ echo "The current directory is $PWD according to the variable \"\$PWD\"."
The current directory is /tmp according to the variable "$PWD".

verwandte Informationen