Bashの発呼者認識機能

Bashの発呼者認識機能

呼び出し側で複数の変数を効果的に宣言して割り当てる必要がある関数(=callee)があります。また、発信者の名前が何であるかを知ることができるはずです。

evalこれで、呼び出し元が編集した渡された変数に文字列を返すことで、電子を実行します。

 write_local_var_assignments variable_name; eval "$variable_name"

"$FUNCNAME"私は、呼び出し側を通過させるか、呼び出し側に組み込みcaller関数を呼び出してその出力を解析することで後者を達成できると思います。

これらすべての解決策は不器用なように見えるので、2つの質問があります。

  1. 呼び出し受信者は、呼び出し元の協力なしに呼び出し元のコンテキストにローカル変数を割り当てることができますか?

つまり、次のように圧縮できます。

 write_local_var_assignments variable_name; eval "$variable_name"

今すぐ入場してください

 run_local_var_assignments

  1. 関数呼び出し元の名前を取得するより良い方法はありますか?構文解析や命令置換なしですぐに結果を得ることができれば良いようです。

答え1

bash(およびksh88、、、、)では、mkshローカルyash変数の範囲は動的です。dashzsh

このコードは:

f() { a=2; echo "f: $a"; }
g() { local a=1; f; echo "g: $a"; }
a=0
g
echo "global: $a"

次の出力を生成します。

f: 2
g: 2
global: 0

から呼び出されるf更新g用の変数です。$ag

typesetこれは、inを使用して宣言された変数、構文()を使用して宣言された関数、またはinを使用して宣言された変数とは対照的です。ここで以下を取得します。kshfunction f { ...; }ksh93privatezsh

f: 2
g: 1
global: 2

したがって、この場合は何もする必要はありません。

呼び出す関数の名前を知るには、bash次のように使用できます。${FUNCNAME[1]}

これに対応するzshのは次のとおりです$funcstack[2]

$ zsh -c 'f() { echo $funcstack[2]; }; g() { f; }; g'
g
$ bash -c 'f() { echo "${FUNCNAME[1]}"; }; g() { f; }; g'
g

答え2

コマンド置換を使用しても問題ない場合は、自己評価文字列を呼び出し元に返すことで、run_local_var_assignments次のように生成された関数を呼び出すことができる関数があります。

$(run_local_var_assignments)

関数は次のとおりです。

emit () {
  local IFS=$'\n'
  printf 'eval eval %q' "$*"
}

eval "$variable_name"上記の評価文を発行します。結果行の最初の項目なので、bashはコマンドで実行された評価を実行します。

この関数によって実行される二重評価と%qエスケープは、呼び出し元に改行やその他の特殊文字を正しく渡すために必要なために存在します。

その後、関数は次のように書くことができます。

run_local_var_assignments () {
  local assignments=()
  assignments+=( 'local myvar1="my value1"' )
  assignments+=( 'local myvar2="my value2"' )
  emit "${assignments[@]}"
}

割り当てはあたかもソースコードであるかのように書かれているので、上記のように値に空白のようなものは引用が必要です。

この回答の上部に示すように、コマンド置換でこの関数を呼び出すと、呼び出し元の範囲にこれらの値を持つこれらのローカル変数が生成されます。

ステートメント配列の代わりに通常の文字列や区切り文字を使用することもできますが、ステートメントブロックを動的に構成するために配列アプローチが役に立つことが多いので、もっと複雑であってもそれを見せたいと思いました。

関連情報