GNU/Linux >> Linux の 問題 >  >> Linux

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の場合、2行目でも同じことについて警告します。 スクリプト内の変数の名前はvar 代わりに。

varが欲しいのですが 変数は各関数に対してローカルであるため、typesetを使用します 、しかし、Bashは、nameref自体と同じ名前の変数にnamerefを「逆参照」することを好まないようです。 local -nを使用できません またはdeclare -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 "%sn" "$var"
}

var="hello"
bug var

結果はbash: warning: var: circular name referencevar 関数内で異なるスコープを持つ必要があります varから グローバルスコープで。これにより、発信者に不要な制限が課せられます。制限は、「この関数では(ローカルの)namerefと名前が衝突する可能性があるため、変数に任意の名前を付けることはできません」です。

関連:rootユーザーからnologinシェルを持つ別のユーザーに切り替える方法は?

承認された回答:

チェット・ラミー(バッシュメンテナー)は言う

今年の初めに、バグバッシュのnamerefについて広範な議論がありました。
この動作を変更する方法について合理的な提案があります。
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.

Linux
  1. Bashシェルのカスタマイズ

  2. コマンドはZshで見つかりませんが、Bashで見つかりましたか?

  3. bashスクリプトを終了する方法はありますが、ターミナルを終了しない

  1. Conda コマンドはコマンド プロンプトでは機能するが、bash スクリプトでは機能しない

  2. Bash がどこにでもあるのはなぜですか (すべてではないにしても、ほとんどの Linux ディストリビューションで)。

  3. bash - すべてのディレクトリ (およびコンテンツ) を削除しますが、pwd 内のファイルは削除しません

  1. エクスポートされたシェル変数とBashにないシェル変数の違いは?

  2. `ssh <host>` はログイン シェルですが、`ssh <host> <command>` は違いますか?

  3. SCP を許可するが、SSH を使用した実際のログインは許可しない