web-dev-qa-db-ja.com

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:
_

KornShell93は私が望むことを正確に実行しますが、Bashは失敗し、スクリプト内のsomething変数の名前がvarの場合、2行目でも同じことを警告します。

var変数を各関数に対してローカルにしたいので、typesetを使用しますが、Bashは、nameref自体と同じ名前の変数にnamerefを「逆参照」することを好まないようです。 _local -n_または_declare -n_は、これらが不足しているkshに割り込むため、使用できません。使用しても問題は解決しません。

私が見つけた唯一の解決策は、各関数で一意の変数名を使用することです。これはローカルであるため、かなりばかげているようです。

Bashのマニュアルには、typesetについて次のように書かれています。

typeset [...]

_-n_各名前にnameref属性を付けて、別の変数への名前参照にします。その他の変数は、nameの値によって定義されます。 _-n_属性自体の変更を除いて、nameへのすべての参照と割り当ては、nameの値によって参照される変数に対して実行されます。

[...]

関数で使用する場合、_-g_オプションが指定されていない限り、declareおよびtypesetは、localコマンドと同様に、各名前をローカルにします。変数名の後に_=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とは異なるスコープを持つ必要があります。これにより、発信者に不要な制限が課せられます。 「この関数では(ローカル)namerefと名前が衝突する可能性があるため、変数に任意の名前を付けることはできません」という制限があります。

6
Kusalananda

Chet Ramey(Bashメンテナ) 言う

今年の初めに、バグバッシュの名前参​​照について広範な議論がありました。この動作を変更する方法について合理的な提案があり、bash-4.4がリリースされた後に検討します。

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


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

$ 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

これは、それが機能することを示していますが、いくつかの警告もあります。

関連する [〜#〜] news [〜#〜] エントリは言う

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