Na het lezen van 24.2. Lokale variabelen , dacht ik dat het declareren van een variabele var
met het trefwoord local
betekende dat var
“s waarde was alleen toegankelijk binnen het codeblok dat wordt afgebakend door de accolades van een functie.
Na het uitvoeren van het volgende voorbeeld kwam ik er echter achter dat var
kan ook worden geopend, gelezen en geschreven vanuit de functies die door dat codeblok worden aangeroepen – dwz zelfs als var
is gedeclareerd local
naar outerFunc
, innerFunc
kan het nog steeds lezen en de waarde ervan wijzigen.
#!/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}]"
Uitvoer:
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 : Is dat een bug in mijn shell (bash 4.3.42, Ubuntu 16.04, 64bit) of is het het verwachte gedrag?
EDIT: Opgelost. Zoals opgemerkt door @MarkPlotnick, is dit inderdaad het verwachte gedrag.
Opmerkingen
Answer
Shell-variabelen hebben een dynamisch bereik . Als een variabele wordt gedeclareerd als lokaal voor een functie, blijft die scope bestaan totdat de functie terugkeert, ook tijdens het aanroepen van andere functies.
Er zijn twee uitzonderingen:
-
in ksh93, als een functie is gedefinieerd met de standaard
function_name () { … }
-syntaxis, gehoorzamen de lokale variabelen aan dynamische scoping. Maar als een functie is gedefinieerd met de ksh-syntaxisfunction function_name { … }
, dan gehoorzamen de lokale variabele lexicale / statische scoping, zodat ze niet zichtbaar zijn in andere functies die hierdoor worden aangeroepen. -
de
zsh/private
plug-in voor automatisch laden inzsh
biedt eenprivate
trefwoord / ingebouwd dat kan worden gebruikt om een variabele met statische reikwijdte te declareren.
ash, bash, pdksh en afgeleiden, bosh hebben alleen dynamische scoping.
Opmerkingen
- Hebben alle variabelen in de shell een dynamisch bereik of is dit alleen van toepassing op variabelen die zijn gedeclareerd met
local
? - @HaroldFischer Alle variabelen hebben een dynamisch bereik. Met een
typeset
ofdeclare
oflocal
declaratie, is het bereik totdat de functie terugkeert. Zonder zon verklaring is de scope globaal. - IMHO,
If a variable is declared as local to a function, that scope remains until the function returns.
is niet genoeg om uit te leggen wat dynamische scope versus lexicale scope is. De beschrijving alleen wordt ook toegepast op lexicale scope. - @jinbeomhong Nee, met lexicale scope is een variabele van een functie niet zichtbaar terwijl deze functie een andere functie aanroept. Ik ‘ heb een zin toegevoegd om dit expliciet te vermelden.
- Heeft dit ook invloed op het aanroepen van ingebouwde functies? Of hebben ingebouwde versies hun eigen bereik?
Antwoord
Het is geen “bug”, de oproep binnen de context van de outerFunc gebruikt die lokale kopie van $ var. De “local” in outerFunc betekent dat de globale niet is gewijzigd. Als je innerFunc buiten outerFunc aanroept, dan zal er een wijziging zijn in de global $ var, maar niet de outerFunc s lokale $ var. Als je local aan innerFunc hebt toegevoegd, dan zal outerFunc s $ var niet worden gewijzigd – in wezen “zouden er 3 zijn:
- $ global :: var
- $ outerFunc :: var
- $ innerFunc :: var
om de naamruimte-indeling van Perl te gebruiken, soort van.
Antwoord
In function innerFunc()
is de var="new value"
niet “gedeclareerd als lokaal , daarom is het beschikbaar in een zichtbaar bereik (eenmaal de functie is aangeroepen).
Omgekeerd werd in function outerFunc()
de local var="initial value"
gedeclareerd als local , daarom is het niet beschikbaar in de globale scope (zelfs als de functie is aangeroepen).
Omdat innerFunc()
werd aangeroepen als een kind van outerFunc()
, var valt binnen het lokale bereik van outerFunc()
.
man 1 bash
kan helpen verduidelijken
local [optie] [naam [= waarde] …]
Voor elk argument, een lokale variabele met de naam naam wordt gemaakt, en een toegewezen waarde. De optie kan een van de opties zijn die door aangifte worden geaccepteerd.Wanneer lokaal binnen een functie wordt gebruikt, zorgt dit ervoor dat de variabelenaam een zichtbaar bereik heeft dat beperkt is tot die functie en zijn onderliggende items. …
Het geïmpliceerde gedrag dat wordt verwacht in de beschrijving kan worden bereikt door local var="new value
in function innerFunc()
.
Zoals anderen hebben gezegd, is dit geen bug in de bash-shell. Alles functioneert zoals het hoort.
Opmerkingen
- Uw eerste verklaring is in tegenspraak met wat de gebruiker ziet. Het afdrukken van de waarde van
var
in het globale bereik, na het aanroepen vaninnerFunc
tot en metoutFunc
, doet niet afdrukkennew value
.
Antwoord
U kunt een functie om lokaal bereik te forceren:
sh_local() { eval "$(set)" command eval "\"\$@\"" }
Voorbeeld:
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"
Resultaat:
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]
var
leeg is?var
is globaal ingesteld ininnerFunc
, dus waarom blijft ‘ niet tot het einde van het script?