Nach dem Lesen von 24.2. Lokale Variablen dachte ich, dass das Deklarieren einer Variablen var
mit dem Schlüsselwort local
bedeutet, dass var
„war nur innerhalb des Codeblocks zugänglich, der durch die geschweiften Klammern einer Funktion begrenzt ist.
Nachdem ich jedoch das folgende Beispiel ausgeführt hatte, stellte ich fest, dass var
kann auch über die von diesem Codeblock aufgerufenen Funktionen aufgerufen, gelesen und geschrieben werden – obwohl var
als local
bis outerFunc
, innerFunc
kann es weiterhin lesen und seinen Wert ändern.
#!/usr/bin/env bash function innerFunc() { var="new value" echo "innerFunc: [var:${var}]" } function outerFunc() { local var="initial value" echo "outerFunc: before innerFunc: [var:${var}]" innerFunc echo "outerFunc: after innerFunc: [var:${var}]" } echo "global: before outerFunc: [var:${var}]" outerFunc echo "global: after outerFunc: [var:${var}]"
Ausgabe:
global: before outerFunc: [var:] # as expected, `var` is not accessible outside of `outerFunc` outerFunc: before innerFunc: [var:initial value] innerFunc: [var:new value] # `innerFunc` has access to `var` ?? outerFunc: after innerFunc: [var:new value] # the modification of `var` by `innerFunc` is visible to `outerFunc` ?? global: after outerFunc: [var:]
Q. : Ist das ein Fehler in meiner Shell (Bash 4.3.42, Ubuntu 16.04, 64 Bit) oder ist es das erwartete Verhalten?
BEARBEITEN: Gelöst. Wie von @MarkPlotnick festgestellt, ist dies tatsächlich das erwartete Verhalten.
Kommentare
- Es ist das erwartete Verhalten
- Bin ich der einzige, der es für ‚ hält, dass in der letzten Ausgabezeile der Wert von
var
leer ist?var
wird global ininnerFunc
festgelegt. Warum bleibt ‚ nicht bis zum Ende bestehen? des Skripts?
Antwort
Shell-Variablen haben eine dynamischer Bereich . Wenn eine Variable für eine Funktion als lokal deklariert wird, bleibt dieser Bereich bis zur Rückkehr der Funktion erhalten, auch bei Aufrufen anderer Funktionen.
Es gibt zwei Ausnahmen:
-
Wenn in ksh93 eine Funktion mit der Standardsyntax
function_name () { … }
definiert ist, folgen ihre lokalen Variablen dem dynamischen Gültigkeitsbereich. Wenn eine Funktion jedoch mit der ksh-Syntaxfunction function_name { … }
definiert ist, folgt ihre lokale Variable dem lexikalischen / statischen Gültigkeitsbereich, sodass sie in anderen von dieser aufgerufenen Funktionen nicht sichtbar sind. -
Das
zsh/private
autoloadable Plugin inzsh
bietet eineprivate
Schlüsselwort / Builtin, mit dem eine Variable mit statischem Gültigkeitsbereich deklariert werden kann.
ash, bash, pdksh und Derivate, bosh haben nur einen dynamischen Gültigkeitsbereich.
Kommentare
- Haben alle Variablen in der Shell einen dynamischen Bereich oder gilt dies nur für Variablen, die mit
local
deklariert wurden? - @HaroldFischer Alle Variablen haben einen dynamischen Bereich. Bei einer
typeset
oderdeclare
oderlocal
-Deklaration gilt der Gültigkeitsbereich bis zur Rückkehr der Funktion. Ohne eine solche Deklaration ist der Gültigkeitsbereich global. - IMHO reicht
If a variable is declared as local to a function, that scope remains until the function returns.
nicht aus, um zu erklären, was ein dynamischer Gültigkeitsbereich und ein lexikalischer Bereich ist. Die Beschreibung allein wird auch auf den lexikalischen Bereich angewendet. - @jinbeomhong Nein, im lexikalischen Bereich ist eine Variable aus einer Funktion nicht sichtbar, während diese Funktion eine andere Funktion aufruft. Ich ‚ habe einen Satz hinzugefügt, um dies explizit anzugeben.
- Betrifft dies auch den Funktionsaufruf von Builtins? Oder haben Builtins ihren eigenen Bereich?
Antwort
Es ist kein Fehler, der Aufruf innerhalb des Kontexts of the OuterFunc verwendet diese lokale Kopie von $ var. Das „local“ in OuterFunc bedeutet, dass das globale nicht geändert wird. Wenn Sie innerFunc außerhalb von OuterFunc aufrufen, wird das globale $ var geändert, nicht jedoch das lokale $ var von OuterFunc. Wenn Sie innerFunc „local“ hinzugefügt haben, wird das $ var von OuterFunc nicht geändert – Im Wesentlichen würde es 3 davon geben:
- $ global :: var
- $ OuterFunc :: var
- $ innerFunc :: var
, um das Perl-Namespace-Format zu verwenden.
Antwort
In function innerFunc()
wurde die var="new value"
nicht als local deklariert, daher ist sie im sichtbaren Bereich verfügbar (einmal) Die Funktion wurde aufgerufen.)
Umgekehrt wurde in function outerFunc()
die local var="initial value"
als local
Weil innerFunc()
als untergeordnetes Element von aufgerufen wurde outerFunc()
, var liegt im lokalen Bereich von outerFunc()
.
man 1 bash
kann helfen zu klären
local [Option] [Name [= Wert] …]
Für jedes Argument ein lokales Die Variable mit dem Namen name wird erstellt und der Wert zugewiesen. Die Option kann eine der Optionen sein, die durch deklarieren akzeptiert werden.Wenn local innerhalb einer Funktion verwendet wird, hat der Variablenname einen sichtbaren Bereich, der auf diese Funktion und ihre untergeordneten Funktionen beschränkt ist. …
Das in der Beschreibung erwartete implizite Verhalten kann erreicht werden, indem local var="new value
in deklariert wird function innerFunc()
.
Wie andere angegeben haben, ist dies kein Fehler in der Bash-Shell. Alles funktioniert wie es sollte.
Kommentare
- Ihre erste Aussage widerspricht dem, was der Benutzer sieht. Das Drucken des Werts von
var
im globalen Bereich nach dem Aufruf voninnerFunc
überoutFunc
funktioniert nicht druckennew value
.
Antwort
Sie können a verwenden Funktion zum Erzwingen des lokalen Bereichs:
sh_local() { eval "$(set)" command eval "\"\$@\"" }
Beispiel:
x() { z="new value" printf "function x, z = [%s]\n" "$z" } y() { z="initial value" printf "function y before x, z = [%s]\n" "$z" sh_local x printf "function y after x, z = [%s]\n" "$z" } printf "global before y, z = [%s]\n" "$z" y printf "global after y, z = [%s]\n" "$z"
Ergebnis:
global before y, z = [] function y before x, z = [initial value] function x, z = [new value] function y after x, z = [initial value] global after y, z = [initial value]