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:
something
KornShell93は私が望むことを正確に行いますが、Bashは失敗し、スクリプトの変数名が2行目に同じ警告を表示しますvar
。
変数はすべての関数に対してローカルであることを望んでいるvar
ので、これを使用typeset
しますが、Bashはnameref自体と同じ名前を持つ変数に対してnamerefを「逆参照」するのが好きではないようです。local -n
ordeclare -n
がないと競合が発生するため使用できずksh
、そのようにしても問題は解決されません。
私が見つけた唯一の解決策は各関数に固有の変数名を使用してください。、地元なので多少愚かなようです。
Bashのマニュアルには以下が含まれていますtypeset
。
typeset
[...]
-n
各名前にnameref
属性を付与して、他の変数への名前参照になるようにしてください。この他の変数はの値として定義されますname
。name
属性自体を変更することに加えて、すべての参照と割り当ては、名前の値-n
で参照される変数に対して行われます。[...]
関数内で使用するときにこのオプションが指定されていない限り、コマンドを使用するのと同じように、各名前をローカル名に
declare
します。変数名の後に続く場合、その変数の値はに設定されます。typeset
local
-g
=value
value
明らかに、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 reference
。var
機能上範囲が異なるはずです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.