Po przeczytaniu 24.2. Zmienne lokalne , pomyślałem, że zadeklarowanie zmiennej var
ze słowem kluczowym local
oznacza, że var
wartość jest dostępna tylko w bloku kodu ograniczonym nawiasami klamrowymi funkcji.
Jednak po uruchomieniu następujący przykład, okazało się, że var
można również uzyskać, odczytywane i zapisywane z funkcji powołuje tego bloku kodu - czyli choć var
deklaruje local
się outerFunc
, innerFunc
nadal jest w stanie go odczytać i zmienić jego wartość.
#!/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}]"
Wydajność:
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:]
P: Czy to błąd w mojej powłoce (bash 4.3.42, Ubuntu 16.04, 64bit), czy jest to oczekiwane zachowanie?
EDYCJA: rozwiązana. Jak zauważył @MarkPlotnick, jest to rzeczywiście oczekiwane zachowanie.
var
jest pusta?var
jest ustawiony globalnieinnerFunc
, więc dlaczego nie przykleja się do końca skryptu?Odpowiedzi:
Zmienne powłoki mają zakres dynamiczny . Jeśli zmienna zostanie zadeklarowana jako lokalna dla funkcji, zakres ten pozostaje do momentu powrotu funkcji.
Istnieją dwa wyjątki:
w ksh93, jeśli funkcja jest zdefiniowana ze standardową
function_name () { … }
składnią, wówczas jej zmienne lokalne podlegają dynamicznemu zakresowi. Ale jeśli funkcja jest zdefiniowana za pomocą składni ksh,function function_name { … }
wówczas jej zmienna lokalna jest zgodna z zasięgiem leksykalnym / statycznym, więc nie są widoczne w innych wywoływanych przez nią funkcjach.zsh/private
autoloadable pluginzsh
dostarcza zprivate
Hasło / wbudowane, które mogą być wykorzystane do zadeklarować zmienną z zakresu statycznego.ash, bash, pdksh i pochodne, bosh mają tylko dynamiczne określanie zakresu.
źródło
local
?typeset
lubdeclare
lublocal
zasięg jest do momentu powrotu funkcji. Bez takiej deklaracji zakres jest globalny.To nie jest błąd, wywołanie w kontekście externalFunc wykorzystuje lokalną kopię $ var. „Lokalny” w outerFunc oznacza, że globalny nie został zmieniony. Jeśli wywołasz innerFunc poza outerFunc, nastąpi zmiana globalnego $ var, ale nie lokalny $ var varFunc. Jeśli dodałeś „local” do innerFunc, wtedy $ var w externalFunc nie zostałby zmieniony - w istocie byłyby 3 z nich:
aby użyć formatu przestrzeni nazw Perla, w pewnym sensie.
źródło
Możesz użyć funkcji, aby wymusić zasięg lokalny:
Przykład:
Wynik:
Źródło
źródło
W
function innerFunc()
var='new value'
nie został zadeklarowany jako lokalny , dlatego jest ona dostępna w widzialnym zakresie (gdy funkcja została wywołana).I odwrotnie, w
function outerFunc()
local var='initial value'
został uznany jako lokalny , więc to nie jest dostępne w zasięgu globalnym (nawet jeśli funkcja została wywołana).Ponieważ
innerFunc()
został wywołany jako dzieckoouterFunc()
, var jest w lokalnym zasięguouterFunc()
.man 1 bash
może pomóc wyjaśnićImplikowana zachowanie, które jest spodziewane w opisie można osiągnąć poprzez uznanie
local var='new value
wfunction innerFunc()
.Jak powiedzieli inni, nie jest to błąd w powłoce bash. Wszystko działa tak, jak powinno.
źródło
var
w zakresie globalnym, po wywołaniuinnerFunc
przezoutFunc
, nie drukujenew value
.