24.2を読んだ後。ローカル変数、キーワードlocal
を使用して変数var
を宣言すると、var
“の値は、関数の中括弧で区切られたコードのブロック内でのみアクセス可能でした。
しかし、次の例を実行した後、は、そのコードブロックによって呼び出される関数からアクセス、読み取り、書き込みすることもできます。つまり、var
が宣言されている場合でもlocal
からouterFunc
まで、innerFunc
は引き続きそれを読み取って値を変更できます。
#!/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}]"
出力:
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 :それは私のシェル(bash 4.3.42、Ubuntu 16.04、64ビット)のバグですか、それとも予想される動作ですか?
編集:解決しました。 @MarkPlotnickが指摘しているように、これは確かに予想される動作です。
コメント
回答
シェル変数には動的スコープ。変数が関数に対してローカルとして宣言されている場合、そのスコープは、他の関数の呼び出し中も含め、関数が戻るまで残ります。
2つの例外があります。
-
ksh93では、関数が標準の
function_name () { … }
構文で定義されている場合、そのローカル変数は動的スコープに従います。ただし、関数がksh構文function function_name { … }
で定義されている場合、そのローカル変数は字句/静的スコープに従うため、これによって呼び出される他の関数では表示されません。 -
zsh
のzsh/private
自動ロード可能プラグインはprivate
静的スコープで変数を宣言するために使用できるkeyword / builtin。
ash、bash、pdksh、および派生物、boshには動的スコープのみがあります。
コメント
- シェル内のすべての変数に動的スコープがありますか、それとも
local
で宣言された変数にのみ適用されますか? - @HaroldFischerすべての変数には動的スコープがあります。
typeset
またはdeclare
またはlocal
宣言の場合、スコープは関数が戻るまでです。このような宣言がない場合、スコープはグローバルです。 - IMHO、
If a variable is declared as local to a function, that scope remains until the function returns.
は、動的スコープと字句スコープを説明するのに十分ではありません。説明だけが字句スコープにも適用されます。 - @jinbeomhongいいえ、字句スコープでは、この関数が別の関数を呼び出している間、関数の変数は表示されません。 'これを明示的に示す文を追加しました。
- これは関数呼び出しビルトインにも影響しますか?または、ビルトインには独自のスコープがありますか?
回答
これはバグではなく、コンテキスト内の呼び出しです。のouterFuncは、$ varのローカルコピーを使用します。outerFuncの「ローカル」は、グローバルが変更されていないことを意味します。 externalFuncの外部でinnerFuncを呼び出すと、グローバル$ varは変更されますが、outerFuncのローカル$ varは変更されません。innerFuncに「local」を追加した場合、outerFuncの$ varは変更されません。 -本質的には、次の3つがあります:
- $ global :: var
- $ outsideFunc :: var
- $ innerFunc :: var
Perlの名前空間形式を使用するには、ある種。
回答
function innerFunc()
では、var="new value"
は local として宣言されていなかったため、可視スコープで使用できます(1回)関数が呼び出されました)。
逆に、function outerFunc()
では、local var="initial value"
が local <として宣言されました。 / em>、したがって、グローバルスコープでは使用できません(関数が呼び出された場合でも)。
innerFunc()
がの子として呼び出されたためouterFunc()
、varはouterFunc()
のローカルスコープ内にあります。
man 1 bash
明確にするのに役立つかもしれません
ローカル[オプション] [名前[=値] …]
各引数について、ローカルnameという名前の変数が作成され、値が割り当てられます。オプションは、declareによって受け入れられたオプションのいずれかです。関数内でlocalを使用すると、変数名のスコープがその関数とその子に制限されます。 …
説明で期待される暗黙の動作は、でlocal var="new value
を宣言することで実現できます。 function innerFunc()
。
他の人が述べているように、これはbashシェルのバグではありません。すべてが正常に機能しています。
コメント
- 最初のステートメントは、ユーザーに表示されている内容と矛盾します。
outFunc
を介してinnerFunc
を呼び出した後、グローバルスコープでvar
の値を出力すると印刷しないnew value
。
回答
ローカルスコープを強制する関数:
sh_local() { eval "$(set)" command eval "\"\$@\"" }
例:
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"
結果:
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
の値が空であると考えるのは、唯一の人ですか?var
はinnerFunc
でグローバルに設定されているのに、なぜ'最後まで固執しないのですかスクリプトの?