Umfang lokaler Variablen in Shell-Funktionen

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.

Online ausführen

#!/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 in innerFunc 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:

  1. 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-Syntax function function_name { … } definiert ist, folgt ihre lokale Variable dem lexikalischen / statischen Gültigkeitsbereich, sodass sie in anderen von dieser aufgerufenen Funktionen nicht sichtbar sind.

  2. Das zsh/private autoloadable Plugin in zsh bietet eine private 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 oder declare oder local -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 , daher ist es im globalen Bereich nicht verfügbar (auch wenn die Funktion aufgerufen wurde).

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 von innerFunc über outFunc funktioniert nicht drucken new 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] 

Quelle

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.