Möglicher Fehler in Bash ?: foo () {echo “$ {var [0]}”; }; var = (bar baz) foo

22

Betriebssystem : Ubuntu 16.04.3

Shell : Bash 4.3.48


Ich weiß, dass es möglich ist, den Inhalt einer Variablen wie in vorübergehend zu ändern var=value command, was wahrscheinlich IFS= read -r varder bemerkenswerteste Fall ist.

Und dank Gregs Wiki verstehe ich auch:

# Why this
foo() { echo "$var"; }
var=value foo

# And this does work
var=value; echo "$var"

# But this doesn't
var=value echo "$var"

Was meinem Verständnis entgeht, ist folgendes:

$ foo() { echo "${var[0]}"; }
$ var=(bar baz) foo
(bar baz)

Soweit ich weiß (und nach der Logik der vorherigen Beispiele), sollte es nicht gedruckt barwerden (bar baz).

Passiert das nur mir? Ist das das beabsichtigte Verhalten und ich vermisse etwas? Oder ist das ein Bug?

nxnev
quelle
3
Vielleicht hat es etwas damit zu tun, dass Bash keine Arrays als Umgebungsvariablen unterstützt?
Jesse_b
3
@ Jesse_b Vielleicht. Wenn ich export var=(foo bar); echo "${var[0]}"es drucke foo, nicht (foo bar).
nxnev
1
Seltsam, das hat auch bei mir funktioniert. Und mit exportihm zeigt:declare -ax var=([0]="foo" [1]="bar")
Jesse_b
3
Die Umgebung darf keine Arrays enthalten, AFAIK. ZB export i_am_array=(foo bar); /usr/bin/env | grep i_am_arraygibt hier keine Ausgabe aus.
Derobert
3
Außerdem: foo() { declare -p var; } ; var=(bar baz) foogibt declare -x var="(bar baz)"Bestätigung, dass es als Zeichenfolge behandelt wird, nicht als Array
derobert

Antworten:

19

Generell anrufend:

var=value cmd

wo cmdist eine funktion ist nicht portabel.

Mit bashfunktioniert dies nur für skalare Variablen (und x=(...)wenn sie als Array analysiert, aber als Skalar zugewiesen wurden). Wenn Sie dies tun, gibt es eine Reihe von Problemen mit dem Gültigkeitsbereich. Mit ksh93und yashfunktioniert dies, aber die Variablendefinition bleibt danach erhalten. Mit erhalten mkshSie einen Syntaxfehler. In der Bourne-Shell funktionierte das überhaupt nicht, auch nicht für skalare Variablen.

Beachten Sie auch, dass selbst bei skalaren Variablen die Angabe, ob die Variable innerhalb der Funktion exportiert (dh an auszuführende Befehle übergeben) wird, von Shell zu Shell unterschiedlich ist (in bash, yash, mksh, zsh, aber nicht in ksh). Asche).

Es funktioniert nur so, wie Sie es erwarten zsh. Beachten Sie, dass zshArray-Indizes bei 1 beginnen.

bash-4.4$ zsh
$ a=(before value)
$ f() echo $a[1]
$ a=(temp value) f
temp
$ echo $a[1]
before
Stéphane Chazelas
quelle
12

Es ist nicht nur ein Fehler, es scheint eine nicht implementierte Funktion zu sein, ohne dass dies jemals geplant ist. Dieser Mailinglisten-Beitrag aus dem Jahr 2014 hat folgende Angaben des Erstellers:

Glücklicherweise können Sie in Bash 4.3 (Patchlevel 25) nicht einfach -DARRAY_EXPORT ausführen und den Import / Export von Array-Variablen durchführen. Der Code wird nicht kompiliert, und wenn Sie dies beheben, wird er nicht verknüpft. Wenn Sie dies beheben, tritt das folgende Problem auf.

Das ist eine Menge Mühe, nur dafür durchzumachen. Ich habe keine Pläne, den Array-Export zu aktivieren.

Das Ziehen aus dem neuesten Git-Repo für Bash hat dies in variables.c:

  #  if ARRAY_EXPORT
        /* Array variables may not yet be exported. */

Das Vorschlagen, was auch immer da ist, ist nicht vollständig.


quelle
5
In diesem Fall handelt es sich um eine Funktion, sodass Sie nichts exportieren müssen, da kein execve()Systemaufruf erforderlich ist. Siehe zshfür eine Schale , die unterstützen Funktionen mit einer Reihe Aufruf auf diese Weise vorübergehend eingestellt.
Stéphane Chazelas
@ StéphaneChazelas Aber die Umgebung ändert sich (durch Hinzufügen einer neuen Variablen) und kehrt dann zurück, nachdem die Funktion abgeschlossen ist (ich bin über diesen Fall:) my_var=one func_bar. Können wir sagen, dass dies exportder Umwelt zugutekommt und der Export hier unter der Haube betrieben wird? Schau dir meine Antwort an, ich habe den Demo-Code hinzugefügt.
MiniMax
10

Aus der man bashBUGS Sektion (die Version von bashist 4.3):

BUGS

   Array variables may not (yet) be exported.

Der nächste Code zeigt, dass eine temporäre Variable nur in der Umgebung vorhanden ist, während die Funktion ausgeführt wird. Wenn die Funktion abgeschlossen ist, verschwindet die temporäre Variable.

### defining the "bar" function
### it pass all environment variables to the "grep" command
### and the "grep" prints the only "my_var" variable from it
bar() { env | grep my_var=; }

### calls the "bar" function with the temporary 
### variable "my_var" created and assigned.
my_var=one bar

my_var=one         ### The output. The environment contains the "my_var" variable

### checks, does the environment still have the "my_var" variable
### (It doesn't have.)
env | grep my_var=
                   ### The output is empty,
                   ### the environment doesn't contain the "my_var" variable

Verwandte Informationen:

MiniMax
quelle