Efter at have læst 24.2. Lokale variabler , jeg troede, at erklæring af en variabel var
med nøgleordet local
betød, at var
“s værdi var kun tilgængelig inden for den blok af kode, der var afgrænset af en funktions krøllede seler.
Efter at have kørt følgende eksempel fandt jeg ud af, at var
kan også tilgås, læses og skrives fra de funktioner, der påkræves af den kodeblok – dvs. selvom var
erklæres local
til outerFunc
, innerFunc
er stadig i stand til at læse den og ændre dens værdi.
#!/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}]"
Output:
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 : Er det en fejl i min shell (bash 4.3.42, Ubuntu 16.04, 64bit) eller er det den forventede adfærd?
REDIGER: Løst. Som bemærket af @MarkPlotnick, er dette faktisk den forventede adfærd.
Kommentarer
Svar
Shell-variabler har en dynamisk omfang . Hvis en variabel erklæres som lokal for en funktion, forbliver dette omfang, indtil funktionen vender tilbage, herunder under opkald til andre funktioner.
Der er to undtagelser:
-
i ksh93, hvis en funktion er defineret med standard
function_name () { … }
syntaksen, så overholder dens lokale variabler dynamisk scoping. Men hvis en funktion er defineret med ksh-syntaksenfunction function_name { … }
så overholder dens lokale variabel leksikal / statisk scoping, så de er ikke synlige i andre funktioner kaldet af dette. -
zsh/private
autoladable plugin izsh
giver etprivate
nøgleord / indbygget, som kan bruges til at erklære en variabel med statisk omfang.
aske, bash, pdksh og derivater, bosh har kun dynamisk scoping.
Kommentarer
- Har alle variabler i skallen et dynamisk omfang, eller gælder dette kun for variabler, der er deklareret med
local
? - @HaroldFischer Alle variabler har dynamisk omfang. Med en
typeset
ellerdeclare
ellerlocal
erklæring er omfanget, indtil funktionen vender tilbage. Uden en sådan erklæring er omfanget globalt. - IMHO,
If a variable is declared as local to a function, that scope remains until the function returns.
er ikke nok til at forklare, hvad der er dynamisk omfang i forhold til leksikalt omfang. Beskrivelsen alene anvendes også til leksikalt omfang. - @jinbeomhong Nej, med leksikalt omfang er en variabel fra en funktion ikke synlig, mens denne funktion kalder en anden funktion. Jeg ' har tilføjet en sætning for at udtrykke dette eksplicit.
- Påvirker dette også funktionskaldende indbyggede? Eller har indbyggede deres eget anvendelsesområde?
Svar
Det er ikke en fejl, opkaldet inden for konteksten af outerFunc bruger den lokale kopi af $ var. Den “lokale” i outerFunc betyder, at det globale ikke ændres. Hvis du kalder innerFunc uden for outerFunc, vil der være en ændring i den globale $ var, men ikke den ydre Funcs lokale $ var. Hvis du tilføjede “lokal” til innerFunc, ville ydreFunc “s $ var ikke blive ændret – i det væsentlige ville der være tre af dem:
- $ global :: var
- $ outerFunc :: var
- $ innerFunc :: var
for at bruge Perls navnepladsformat, slags.
Svar
I function innerFunc()
blev var="new value"
ikke erklæret som lokal , derfor er den tilgængelig i synligt omfang (en gang funktionen er blevet kaldt).
Omvendt blev function outerFunc()
local var="initial value"
erklæret som lokal , derfor er den ikke tilgængelig i det globale omfang (selvom funktionen er blevet kaldt).
Fordi innerFunc()
blev kaldt som barn af outerFunc()
, var ligger inden for det lokale omfang af outerFunc()
.
man 1 bash
kan hjælpe med at afklare
local [option] [name [= value] …]
For hvert argument er et lokalt variablenavnet navn oprettes og tildeles værdi. Indstillingen kan være en hvilken som helst af de muligheder, der accepteres af erklæringen.Når lokalt bruges inden for en funktion, får det variabelnavnet til at have et synligt omfang begrænset til den funktion og dens børn. …
Den underforståede adfærd, som forventes i beskrivelsen, kunne opnås ved at erklære local var="new value
i function innerFunc()
.
Som andre har sagt, er dette ikke en fejl i bash-skallen. Alt fungerer som det skal.
Kommentarer
- Dit første udsagn modsiger det, som brugeren ser. Udskrivning af værdien af
var
i det globale omfang efter opkald tilinnerFunc
gennemoutFunc
udskriver ikkenew value
.
Svar
Du kan bruge en funktion til at tvinge lokalt omfang:
sh_local() { eval "$(set)" command eval "\"\$@\"" }
Eksempel:
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"
Resultat:
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
på den sidste outputlinje er tom?var
er indstillet globalt iinnerFunc
, så hvorfor holder det ikke ' til slutningen af scriptet?