Omfanget av lokale variabler i skallfunksjoner

Etter å ha lest 24.2. Lokale variabler , jeg tenkte at å erklære en variabel var med nøkkelordet local betydde at var «s verdi var bare tilgjengelig i kodeblokken avgrenset av krøllbøylene til en funksjon.

Imidlertid, etter å ha kjørt følgende eksempel, fant jeg ut at var kan også nås, leses og skrives fra funksjonene påkalt av kodeblokken – dvs. selv om var blir erklært local til outerFunc, innerFunc er fremdeles i stand til å lese den og endre verdien.

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

Utgang:

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 feil i skallet mitt (bash 4.3.42, Ubuntu 16.04, 64bit) eller er det forventet oppførsel?

EDIT: Løst. Som bemerket av @MarkPlotnick, er dette virkelig den forventede atferden.

Kommentarer

  • Det er den forventede atferden
  • Er jeg den eneste som synes det ' er rart at verdien på var på den siste utgangslinjen er tom? var er satt globalt i innerFunc, så hvorfor holder det ikke ' til slutten av skriptet?

Svar

Shell-variabler har en dynamisk omfang . Hvis en variabel blir erklært som lokal for en funksjon, forblir dette omfanget til funksjonen returnerer, inkludert under samtaler til andre funksjoner.

Det er to unntak:

  1. i ksh93, hvis en funksjon er definert med standard function_name () { … } syntaksen, så følger de lokale variablene dynamisk omfang. Men hvis en funksjon er definert med ksh-syntaksen function function_name { … }, følger den lokale variabelen leksikalsk / statisk avgrensning, så de er ikke synlige i andre funksjoner som kalles dette. li>

  2. zsh/private autoladable plugin i zsh gir en private nøkkelord / innebygd som kan brukes til å erklære en variabel med statisk omfang.

ask, bash, pdksh og derivater, bosh har bare dynamisk scoping.

Kommentarer

  • Har alle variablene i skallet et dynamisk omfang, eller gjelder dette bare variabler erklært med local?
  • @HaroldFischer Alle variabler har dynamisk omfang. Med en typeset eller declare eller local -erklæring, er omfanget til funksjonen returnerer. Uten en slik 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 å forklare hva som er dynamisk omfang i forhold til leksikalt omfang. Beskrivelsen alene blir også brukt på leksikalt omfang.
  • @jinbeomhong Nei, med leksikalt omfang er en variabel fra en funksjon ikke synlig mens denne funksjonen kaller en annen funksjon. Jeg ' har lagt til en setning for å uttrykke dette eksplisitt.
  • Påvirker dette også funksjonskalling innebygde? Eller har innebygde sitt eget omfang?

Svar

Det er ikke «en feil, samtalen i konteksten av outerFunc bruker den lokale kopien av $ var. Den «lokale» i outerFunc betyr at det globale ikke er endret. Hvis du kaller innerFunc utenfor den ytre Func, vil det være en endring i den globale $ var, men ikke den ytre Funcs lokale $ var. Hvis du la til «lokal» til innerFunc, ville ikke ytre Func «s $ var ikke endret – i hovedsak ville det være tre av dem:

  • $ global :: var
  • $ outerFunc :: var
  • $ innerFunc :: var

for å bruke Perls navneplassformat, liksom.

Svar

I function innerFunc() ble var="new value" ikke erklært som lokal , derfor er den tilgjengelig i synlig omfang (en gang funksjonen har blitt kalt).

Omvendt ble function outerFunc() local var="initial value" erklært som lokal , derfor er den ikke tilgjengelig i det globale omfanget (selv om funksjonen er blitt kalt).

Fordi innerFunc() ble kalt som barn av outerFunc(), var ligger innenfor det lokale omfanget av outerFunc().

man 1 bash kan bidra til å avklare

local [option] [name [= value] …]

For hvert argument, et lokalt variabel med navn blir opprettet og tildelt verdi. Alternativet kan være hvilket som helst av alternativene som godtas av erklær.Når lokalt brukes i en funksjon, fører det til at variabelnavnet har et synlig omfang begrenset til den funksjonen og dens barn. …

Den underforståtte oppførselen som forventes i beskrivelsen kan oppnås ved å erklære local var="new value i function innerFunc().

Som andre har uttalt, er dette ikke en feil i bash-skallet. Alt fungerer som det skal.

Kommentarer

  • Din første uttalelse strider mot det brukeren ser. Hvis du skriver ut verdien av var i det globale omfanget, etter å ha ringt innerFunc gjennom outFunc, gjør ikke skriv ut new value.

Svar

Du kan bruke en funksjon for å 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

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *