Bash: Arithmetische Erweiterung, Parametererweiterung und der Kommaoperator

Bash: Arithmetische Erweiterung, Parametererweiterung und der Kommaoperator

Ich habe eine Frage zur Parametererweiterung von Bash innerhalb eines Komma-Ausdrucks innerhalb eines arithmetischen Ausdrucks. Ich habe zwei Anweisungen, von denen ich dachte, dass sie gleichwertig sein sollten, was aber nicht der Fall ist.

Warum funktioniert die Bash-Zeile

n=3; k=10; echo $((n++,k=$n))

Ausgabe 3statt 4? (Es wird wie erwartet nauf gesetzt, setzt aber auf .)4k3

Im Gegensatz dazu die Bash-Zeile

 n=3; k=10; echo $((n++,k=n))

gibt aus 4, wie ich erwartet habe. (Es setzt nauf 4und auch kauf 4.)

Ich habe versucht, in beiden Bash-Zeilen „with“, „with“ und „with“ zu ersetzen n++, ++nund n=n+1es n=$((n+1))kommt bei allen zur gleichen Diskrepanz: k=$n„ergibt“ 3in allen Skripten und k=n„ergibt“ 4in allen.


Nach meinem Verständnis sollten, wenn der Wert von neine Ganzzahl ist (was er ist), $nund ninnerhalb eines arithmetischen Ausdrucks denselben Wert haben. (Und dies ist aufgrund der (( ... ))Konstruktion ein arithmetischer Ausdruck.) Laut dem Bash-Handbuch im Abschnitt Arithmetische Auswertung in einem arithmetischen Ausdruck:

   Shell variables are allowed as  operands;  parameter  expansion  is  performed  before  the
   expression  is  evaluated.  Within an expression, shell variables may also be referenced by
   name without using the parameter expansion syntax.

Warum behandelt Bash also $nanders als nin diesem Beispiel und wie genau wird es ausgewertet $n?


Ich konnte das Problem nicht reproduzieren, ohne den Komma-Operator zu verwenden. Soweit ich das immer gesehen habe, berechnet der Komma-Operator jeden seiner Komponentenunterausdrücke von links nach rechts, einschließlich aller Nebeneffekte jeder Komponente, wenn diese Komponente berechnet wird. Der Wert des Komma-Ausdrucks ist dann der Wert der zuletzt berechneten Komponente (die ganz rechts).


Diese Frage trat im Zusammenhang mit einem viel komplizierteren Skript auf und ich konnte sie schließlich auf dieses einfache Beispiel reduzieren, das das Problem veranschaulicht.

Also, was verstehe ich falsch, wenn es um arithmetische Erweiterung, Parametererweiterung oder den Kommaoperator geht?

Beachten Sie, dass ich nicht nach einer Problemumgehung suche, da ich bereits eine habe: Die Version mit nanstelle von $nfunktioniert wie erwartet. Ich möchte nur verstehen, was Bash in der Version mit macht $nund warum es etwas anderes macht als die Version mit nur n.

Antwort1

Die Shell-Parametererweiterung erfolgtbevor der Ausdruck ausgewertet wird, einschließlich der Kommabehandlung:

Der Ausdruck wird so behandelt, als stünde er in Anführungszeichen, aber ein Anführungszeichen innerhalb der Klammern wird nicht speziell behandelt. Alle Token im Ausdruck werden einer Parameter- und Variablenerweiterung, Befehlsersetzung und Entfernung von Anführungszeichen unterzogen. Das Ergebnis wird als der auszuwertende arithmetische Ausdruck behandelt.

Sie können dies sehen mit

unset n
echo $((n++,k=$n))

Die Fehlermeldung

bash: n++,k=: syntax error: operand expected (error token is "=")

zeigt, dass $nersetzt wird, bevor der gesamte arithmetische Ausdruck verarbeitet wird.

In Ihrem Fall ist der Ausdruck, der ausgewertet wird,

n++,k=3

Antwort2

Darin $((...))wird zuerst die Erweiterung¹ wie innerhalb von Anführungszeichen durchgeführt und dann das Ergebnis ausgewertet.

In n=3; k=10; echo $((n++,k=$n))(oder n=1; echo "$((++n + $n))", das ist nicht auf beschränkt ,) ist der ausgewertete arithmetische Ausdruck also n++, k=3.

Hierfür benötigen Sie:

n=3; k=10; echo "$((n++,k=n))"

(Beachten Sie auch die Anführungszeichen, da die arithmetische Erweiterung wie andere Formen der Worterweiterung in POSIX-Shells Split+Glob unterliegt.)


¹, Sie werden einige Variationen finden, wo Arrays und assoziative Arrays aufgerufen werden, da einige Shells versuchen werden, das $((hash[$key]++))korrekt zu handhaben, wenn es zum Beispiel $keyenthält]

verwandte Informationen