Erstellt `deklarieren -a A` ein leeres Array` A` in Bash?

7

Erstellt declare -a Aein leeres Array Ain Bash oder legt es nur ein Attribut fest, falls Aes später zugewiesen wird?

Betrachten Sie diesen Code:

set -u
declare -a A
echo ${#A[*]}
echo ${A[*]}
A=()
echo ${#A[*]}
echo ${A[*]}
A=(1 2)
echo ${#A[*]}
echo ${A[*]}

Was sollte die erwartete Ausgabe sein?

In Bash 4.3.48 (1) bekomme ich bash: A: unbound variablebeim Abfragen die Anzahl der Elemente danach declare. Ich erhalte diesen Fehler auch beim Zugriff auf alle Elemente. Ich weiß, dass spätere Versionen von Bash dies anders behandeln. Trotzdem möchte ich wissen, ob declaretatsächlich eine Variable definiert ist (um leer zu sein).

U. Windl
quelle
Nun, Sie könnten versuchen declare -a P; Q=(), dann declare -p P Qoder set | grep -w '^[PQ]'zu bash Vorstellung von Ihren Variablen zu zeigen. Befriedigt Sie das oder suchen Sie etwas Tieferes?
Mosvy

Antworten:

14

Dies hängt davon ab, ob die entsprechende Variable bereits zuvor im aktuellen Bereich deklariert wurde (oberste Ebene, auch bekannt als globale oder aktuelle Funktion).

Wenn es im aktuellen Bereich nicht deklariert wurde (und beachten Sie, dass die Variable im Bereich der obersten Ebene möglicherweise durch Importieren aus der Umgebung deklariert (und zugewiesen) wurde), deklariert sie es (macht es lokal für die Funktion Wenn Sie sich im Funktionsumfang befinden, weisen Sie ihm einen Typ zu, initialisieren ihn jedoch nicht, auch nicht einer leeren Liste (wird declare -p aangezeigt declare -a a, nicht so, declare -a a=()als hätten Sie ihn deklariert und / oder zugewiesen a=()).

Wenn es bereits im aktuellen Bereich deklariert wurde (z. B. weil es im globalen Bereich als skalare Variable aus der Umgebung importiert wurde), declare -a awürde versucht , es in ein Array zu konvertieren .

Wenn es zuvor ein Skalar war, wird es zu einem ([0]=value-of-the-variable)Array. Wenn es bereits ein Array war, bleibt es unberührt. Wenn es sich um ein assoziatives Array handelt, schlägt dies mit einem cannot convert associative to indexed arrayFehler fehl .

Beachten Sie, dass declare aein Array oder Hash nicht in einen Skalar konvertiert wird. bashwäre sowieso nicht in der Lage, einen Hash / Array in Skalar zu konvertieren. Sie können declare +aA aeinen Skalar erzwingen (dies würde mit einem Fehler fehlschlagen, wenn die Variable zuvor ein Hash / Array im aktuellen Bereich war).

In Ihrem Fall wurde die Variable wahrscheinlich noch nicht im aktuellen Bereich deklariert, sodass sie deklariert, aber nicht zugewiesen wurde. Dies erklärt, warum der Versuch, sie zu erweitern, unter fehlschlägt set -u.

Diese Unterscheidung zwischen zwei deklarierten und zugewiesenen / gesetzten Zuständen einer Variablen ist nicht spezifisch für bash. In POSIX shkönnen Sie auch exporteine Variable erstellen oder erstellen, readonlyohne einen Wert anzugeben.

$ sh -uc 'unset -v var; readonly var; : "$var"'
sh: 1: var: parameter not set

Beachten Sie, dass unsetdie Variable sowohl deaktiviert als auch nicht deklariert wird. In bash, mkshund yashes kann die Variable aus einem äußeren Bereich wiederherstellen.

In zsh, außer in der shEmulation, typesetdeklariert die Verwendung einer Variablen und setzt sie auf einen leeren Wert, wenn sie nicht bereits festgelegt wurde oder festgelegt wurde, sondern von einem anderen Typ (Skalar vs. Array vs. assoziatives Array).

Stéphane Chazelas
quelle
Mein Fazit ist also, dass, wenn Avorher nicht deklariert wurde declare -a A, Aimmer noch kein Array ist (weil es sonst ein leeres Array mit 0 Elementen wäre), sondern undefiniert. Was ist der Zweck, declare -awenn ich Arrays durch Zuweisung ( A=(), A[0]=...) erstellen kann ?
U. Windl
1
@ U.Windl: Die declare -a/ declare -Adienen nur zur Unterscheidung, wenn Sie das Array mit dem folgenden Namen als indiziertes oder assoziatives Array verwenden möchten. Keiner von ihnen setzt / initialisiert Werte
Inian
2
@ U.Windl, erklären sie es immer noch als ein Array , so dass zum Beispiel a=footun würde , a[0]=foound declare -p aes als ein Array zeigen würde. Aber die Hauptverwendung von declarein in Funktion, um die Funktion lokal für die Funktion zu machen. Es ist wie für export, es weist es nicht zu, sondern merkt sich das exportAttribut, falls die Variable später zugewiesen wird.
Stéphane Chazelas