Befehl und Shell-Erweiterung deklarieren

Befehl und Shell-Erweiterung deklarieren

Ich bin zufällig auf das folgende bash, für mich irgendwie unerwartete Verhalten gestoßen.

# The following works
$ declare bar=Hello                               # Line 1
$ declare -p bar                                  # Line 2
declare -- bar="Hello"
$ foo=bar                                         # Line 3
$ declare ${foo}=Bye                              # Line 4
$ declare -p bar                                  # Line 5
declare -- bar="Bye"
# The following fails, though
$ declare -a array=( A B C )                      # Line 6
$ declare -p array                                # Line 7
declare -a array=([0]="A" [1]="B" [2]="C")
$ foo=array                                       # Line 8
$ declare -a ${foo}=([0]="A" [1]="XXX" [2]="C")   # Line 9
bash: syntax error near unexpected token `('`
# Quoting the assignment fixes the problem
$ declare -a "${foo}=(A YYY C)"                   # Line 10
$ declare -p array                                # Line 11
declare -a array=([0]="A" [1]="YYY" [2]="C")

Seit der Shell-Erweiterung

  1. Klammererweiterung
    • Tilde-Erweiterung
    • Parameter- und Variablenerweiterung
    • Arithmetische Erweiterung
    • Prozesssubstitution
    • Befehlsersetzung
  2. Worttrennung
  3. Dateinamenerweiterung

auf der Befehlszeile ausgeführt wird, nachdem sie in Token aufgeteilt wurde (gefolgt von der Entfernung der Anführungszeichen), aber bevor der letzte Befehl ausgeführt wird. Ich hätte nicht erwartet, dass Zeile 9 fehlschlägt.

Welcher Grund steckt dahinter, weshalb bashZeile 9 nicht akzeptiert wird?Oder anders gesagt,was übersehe ich bei der Verarbeitung von Zeile 9, bashdas zum Scheitern von Zeile 10, aber zum Erfolg von Zeile 10 führt?

In jedem Fall wird das Setzen von Anführungszeichen nicht immer problemlos funktionieren und erfordert besondere Aufmerksamkeit, wenn es sich bei den Array-Elementen um Zeichenfolgen handelt, die beispielsweise Leerzeichen enthalten.

Antwort1

tl;dr; Ich denke, es handelt sich lediglich um eine Syntax-Eigenart und Sie sollten nicht davon ausgehen, dass dahinter eine große Absicht steckt.

Bash verwendet eine von Bison/Yacc generierteParser, aber wie bei vielen anderen Sprachen (C, Perl usw.) ist es kein "sauberer" Parser, sondern behält auch einigeZustandgetrennt/parallel zur Grammatik in der parser_stateVariable.

In dieser Statusvariable wird ein Flag gespeichert : . Dieses wird gesetzt, wenn ein als Token PST_ASSIGNOKanalysiertes integriertes Element Flags enthält.WORDASSIGNMENT_BUILTIN

Solche „Zuweisungs-Builtins“ sind local, typeset, declare, alias, exportund readonly.

Dies PST_ASSIGNOKweist den Parser an, Klammern als Teil eines WORDTokens zu betrachten, wenn sie nach einer Zuweisung rechts von einem solchen Builtin verwendet werden. Es ändert jedoch NICHT die Regeln, die bestimmen, ob das aktuelle Token tatsächlich einAbtretung: Da ${foo}=(...)dies keine akzeptable Zuweisung ist, wird es nicht als einzelnes Wort analysiert und die Klammern lösen wie in einen Syntaxfehler aus echo foo(bar).

Nachdem eine Befehlszeile analysiert wurde, wird sieerweitert, und als Teil der Erweiterungen wird jede zusammengesetzte Zuweisung ( WORDdie mit markiert wurde W_COMPASSIGN) wie var=(1 2)ausgeführt und durch ersetzt var, das dann als Argument an ein integriertes wie übergeben wird declare. Wenn jedoch declarenach allen Erweiterungen ein Argument der Form erhält var=(...), wird es dieses selbst erneut analysieren und erweitern.

Kann also varname=foo; declare "$var=(1 2 3)"ähnlich sein wie declare foo='(1 2 3)'. Oder wie declare foo=(1 2 3), je nachdem, ob die Variable bereits definiert wurde:

$ declare 'foo=(1 2 3)'; typeset -p foo
declare -- foo="(1 2 3)"
$ declare foo=(1); typeset -p foo
declare -a foo=([0]="1")
$ declare 'foo=(1 2 3)'; typeset -p foo
declare -a foo=([0]="1" [1]="2" [2]="3")

Ich glaube nicht, dass es eine gute Idee ist, sich auf diesen Sonderfall zu verlassen:

$ declare 'bar=(1 ( )'; typeset -p bar
declare -- bar="(1 ( )"
$ declare bar=(1); typeset -p bar
declare -a bar=([0]="1")
$ declare 'bar=(1 ( )'; typeset -p bar
bash: syntax error near unexpected token `('

verwandte Informationen