bash シェル関数には循環名参照がありますが、ksh にはありません。

bash シェル関数には循環名参照がありますが、ksh にはありません。

BashとKornShell93で動作することを望む一連のシェル関数を書いていますが、Bashを使用すると「循環名を参照」という警告が表示されます。

問題の本質はこうです。

function set_it {
    typeset -n var="$1"

    var="hello:$var"
}

function call_it {
    typeset -n var="$1"

    set_it var
}

something="boff"
call_it something
echo "$something"

実行してください:

$ ksh script.sh
hello:boff

$ bash script.sh
script.sh: line 4: warning: var: circular name reference
hello:

somethingKornShell93は私が望むことを正確に行いますが、Bashは失敗し、スクリプトの変数名が2行目に同じ警告を表示しますvar

変数はすべての関数に対してローカルであることを望んでいるvarので、これを使用typesetしますが、Bashはnameref自体と同じ名前を持つ変数に対してnamerefを「逆参照」するのが好きではないようです。local -nordeclare -nがないと競合が発生するため使用できずksh、そのようにしても問題は解決されません。

私が見つけた唯一の解決策は各関数に固有の変数名を使用してください。、地元なので多少愚かなようです。

Bashのマニュアルには以下が含まれていますtypeset

typeset[...]

-n 各名前にnameref属性を付与して、他の変数への名前参照になるようにしてください。この他の変数はの値として定義されます namename属性自体を変更することに加えて、すべての参照と割り当ては、名前の値 -n で参照される変数に対して行われます。

[...]

関数内で使用するときにこのオプションが指定されていない限り、コマンドを使用するのと同じように、各名前をローカル名に declareします。変数名の後に続く場合、その変数の値はに設定されます。typesetlocal-g=valuevalue

明らかに、Bashの名前参照と関数ローカル変数にはいくつかの問題があります。

したがって、質問は、この場合、Bashの名前参照変数の処理が欠落しているのですか、それともBashのバグ/バグ機能ですか?

修正する:私は現在、GNU bash, version 4.3.39(1)-release (x86_64-apple-darwin15)そして一緒に働いていますGNU bash, version 4.3.46(1)-release (x86_64-unknown-openbsd6.0)。 macOS に付属している Bash は古すぎるため、名前参照についてはわかりません。

修正する:より短く:

function bug {
    typeset -n var="$1"
    printf "%s\n" "$var"
}

var="hello"
bug var

明らかになるbash: warning: var: circular name referencevar機能上範囲が異なるはずですvarグローバルな観点から。これは呼び出し側に不必要な制限を課します。制限は、「この関数の(ローカル)名前参照と名前の競合が発生する可能性があるため、任意に変数名を指定することはできません」です。

ベストアンサー1

Chet Ramey (Bash マネージャー)説明する

今年初め、バグバスでnamerefについて広範な議論がありました。この動作を変更する方法についての健全な提案があります。 bash-4.4がリリースされた後、それを見てみましょう。

その間、私はローカルのnameref変数の名前を少し難読化して、ライブラリ内で(希望的に)グローバルシェル変数名と衝突しないようにしました。


5.0では、bashこの問題は少し修正されました(しかし実際には修正されませんでした)。観察された動作は次のとおりです。

$ foo () { typeset -n var="$1"; echo "$var"; }
$ var=hello
$ foo var
bash: typeset: warning: var: circular name reference
bash: warning: var: circular name reference
bash: warning: var: circular name reference
hello

これはうまくいきますが、いくつかの注意事項があります。

関連情報項目は言う

i. A nameref name resolution loop in a function now resolves to a variable by
that name in the global scope.

おすすめ記事