Omfanget af lokale variabler i shell-funktioner

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.

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}]" 

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

  • Det er den forventede adfærd
  • Er jeg den eneste, der synes det ' er underligt, at værdien på var på den sidste outputlinje er tom? var er indstillet globalt i innerFunc, så hvorfor holder det ikke ' til slutningen af scriptet?

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:

  1. 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-syntaksen function function_name { … } så overholder dens lokale variabel leksikal / statisk scoping, så de er ikke synlige i andre funktioner kaldet af dette.

  2. zsh/private autoladable plugin i zsh giver et private 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 eller declare eller local 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 til innerFunc gennem outFunc udskriver ikke new 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] 

Kilde

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *