Omfattning av lokala variabler i skalfunktioner

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.

Kör det online

#!/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

  • Det är det förväntade beteendet
  • Är jag den enda som tycker att ' är konstigt att värdet på var på den sista utdataraden är tomt? var ställs in globalt i innerFunc, så varför fastnar det inte ' i skriptet?

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:

  1. 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-syntaxen function function_name { … } så följer dess lokala variabel lexikal / statisk avgränsning, så de är inte synliga i andra funktioner som kallas av detta.

  2. zsh/private autoladdningsbart plugin i zsh har ett private 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 eller declare eller local -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 ringt innerFunc till outFunc gör skriv inte ut new 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] 

Källa

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *