Efter att ha läst 24.2. Lokala variabler , jag trodde att deklarera en variabel var
med nyckelordet local
innebar att var
”-värde var endast tillgängligt inom kodkod som avgränsas av en funktions lockiga hakparenteser.
Efter att ha kört följande exempel fick jag reda på att var
kan också nås, läsas och skrivas från de funktioner som anropas av det kodblocket – dvs. även om var
förklaras local
till outerFunc
, innerFunc
kan fortfarande läsa den och ändra dess värde.
#!/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}]"
Utgång:
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 : Är det ett fel i mitt skal (bash 4.3.42, Ubuntu 16.04, 64bit) eller är det förväntat beteende?
REDIGERA: Löst. Som påpekats av @MarkPlotnick är detta verkligen det förväntade beteendet.
Kommentarer
Svar
Shell-variabler har en dynamiskt omfång . Om en variabel förklaras som lokal för en funktion, förblir det omfånget tills funktionen återgår, inklusive under samtal till andra funktioner.
Det finns två undantag:
-
i ksh93, om en funktion definieras med standarden
function_name () { … }
syntax, så följer dess lokala variabler dynamisk avgränsning. Men om en funktion definieras med ksh-syntaxenfunction function_name { … }
så följer dess lokala variabel lexikal / statisk avgränsning, så de är inte synliga i andra funktioner som kallas av detta. -
zsh/private
autoladdningsbart plugin izsh
har ettprivate
nyckelord / inbyggt som kan användas för att deklarera en variabel med statisk räckvidd.
ask, bash, pdksh och derivat, bosh har bara dynamisk scoping.
Kommentarer
- Har alla variabler i skalet ett dynamiskt omfång eller gäller detta endast variabler som deklareras med
local
? - @HaroldFischer Alla variabler har dynamiskt omfång. Med en
typeset
ellerdeclare
ellerlocal
-deklaration är omfattningen tills funktionen returnerar. Utan en sådan deklaration är omfattningen global. - IMHO,
If a variable is declared as local to a function, that scope remains until the function returns.
räcker inte för att förklara vad som är dynamiskt omfång i förhållande till lexikaliskt omfång. Beskrivningen ensam tillämpas också på lexical scope. - @jinbeomhong Nej, med lexical scope är en variabel från en funktion inte synlig medan denna funktion anropar en annan funktion. Jag ' har lagt till en mening för att uttryckligen ange detta.
- Påverkar detta också funktion som kallar inbyggda? Eller har inbyggda egna räckvidd?
Svar
Det är inte ett fel, samtalet i sammanhanget av den yttre Func använder den lokala kopian av $ var. Den ”lokala” i yttre Func betyder att den globala inte har ändrats. Om du ringer innerFunc utanför yttreFunk, kommer det att ske en förändring av den globala $ var, men inte den yttreFunks lokala $ var. Om du lade till ”lokal” till innerFunc, skulle yttreFunk ”s $ var inte ändras – i huvudsak skulle det finnas tre av dem:
- $ global :: var
- $ outerFunc :: var
- $ innerFunc :: var
för att använda Perls namnområdesformat, typ av.
Svar
I function innerFunc()
förklarades var="new value"
inte som lokal , därför är den tillgänglig i synligt omfång (en gång funktionen har kallats).
Omvänt, i function outerFunc()
förklarades local var="initial value"
som lokal , därför är den inte tillgänglig i det globala omfånget (även om funktionen har anropats).
Eftersom innerFunc()
kallades som barn till outerFunc()
, var ligger inom det lokala omfånget för outerFunc()
.
man 1 bash
kan hjälpa till att klargöra
local [option] [name [= value] …]
För varje argument, en lokal variabelnamnet skapas och tilldelas värde. Alternativet kan vara vilket som helst av de alternativ som accepteras av deklarera.När lokalt används inom en funktion orsakar det att variabelnamnet har ett synligt omfång som är begränsat till den funktionen och dess barn. …
Det underförstådda beteendet som förväntas i beskrivningen kan uppnås genom att deklarera local var="new value
i function innerFunc()
.
Som andra har sagt är detta inte ett fel i bash-skalet. Allt fungerar som det ska.
Kommentarer
- Ditt första uttalande strider mot det som användaren ser. Att skriva ut värdet för
var
i det globala omfånget efter att ha ringtinnerFunc
tilloutFunc
gör skriv inte utnew value
.
Svar
Du kan använda en funktion för att tvinga lokalt omfång:
sh_local() { eval "$(set)" command eval "\"\$@\"" }
Exempel:
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 sista utdataraden är tomt?var
ställs in globalt iinnerFunc
, så varför fastnar det inte ' i skriptet?