1

環境:

コマンドを介して相互にやり取りする Bash スクリプトの大規模なセットによって管理されるインフラストラクチャのいくつかの部分がありsourceます。これには、使用する標準の Bash テンプレートに準拠して作成されたファイルが含まれます (また、頻繁にチェーン インクルードが含まれます)。これはおそらく決して許されるべきではない状況であることはわかっていますが、それが私たちの現状です。

テンプレートは基本的に次のようになります。

set_params() {
    #for parameters in a file that need to be accessed by other methods 
    #in that file and have the same value from initialization of that 
    #file to its conclusion:
    global_param1=value 

    #left blank for variables that are going to be used by other methods 
    #in the file, but don't have a static value assigned immediately:
    global_param2= 
}

main_internals() {
    #user-created code goes here.
}

main() {
    set_params
    #generic setup stuff/traps go here
    main_internals arg arg arg
    #generic teardown stuff goes here
}

この構造を使用して、コマンドを介してファイルに他のファイルをインクルードしsource、インクルード ファイル メソッドを呼び出しますmain。これにより、ほとんどの操作が適切にラップおよびモジュール化されます。

問題:

このインフラストラクチャに関する最も厄介な問題のいくつかは、同じsourced チェーン/ファイル セット内の別の場所で無関係に使用されるグローバル変数名を使用する新しいモジュールがコードベースに追加されるときに発生します。myfileつまり、file1.shに特定の目的で使用されるという変数があり、file2.sh を使用しsourceてさらに何かをmyfile行う場合、file2.sh を書いている人はそれを知りません (多くの場合、できません)。多くのファイルが連鎖していることが予想されます)、file2.sh で呼び出される非ローカル変数myfileを配置し、file1.sh の同じ名前の変数の値を変更する可能性があります。

質問:

localグローバル変数名の競合が発生し、すべてを完全に解決できないと仮定すると、特定の関数またはその下の呼び出しの実行中にグローバルスコープで設定されたすべての変数をプログラムで設定解除する方法はありますか? 問題のスクリプトが保持している同じ名前の他の変数を設定解除せずに設定解除する方法はありますsourceか?

答えは「いいえ」である可能性が非常に高いですが、周りを見回して「変数名を追跡し、使い終わったら何かを設定解除する」以外に何も見つけられなかった後(これは必然的にコストのかかる間違いにつながります)、私は考えました私は尋ねます。

別の言い方をすると、Bash で 3 番目のスコープのように機能するものを作成/ハッキングする方法はありますか? 「関数に対してローカル」と「このファイルで実行されているすべてのファイルと、このファイルsourceによって実行されているすべてのファイルに表示される」の間の何か?

4

1 に答える 1

3

以下は未確認です。

次のように多くの変数を保存できます。

unset __var __vars
saveIFS=$IFS
IFS=$'\n'
__vars=($(declare -p))
IFS=$saveIFS

または、上記の最後の行から次の行を次のように変更して、共通のプレフィックスに基づいて保存します。

__vars=($(declare -p "${!foo@}"))

次に、必要なものの設定を解除できます。

unset foo bar baz

または、共通のプレフィックスに基づいて設定を解除します。

unset "${!foo@}"

変数を復元するには:

for __var in "${__vars[@]}"
do
    $i
done

注意してください

  • 改行が埋め込まれた変数は間違った動作をします
  • 空白を含む値は間違ったことをします
  • 一致する接頭辞パラメーター展開が空の結果を返す場合、declare -pコマンドはすべての変数を返します。

より選択的な別の手法は、現在の関数で使用されている変数を具体的に知っているため、それらを選択的に保存および復元できるようにすることです。

# save
for var in foo bar baz
do
    names+=($var)
    values+=("${!var}")
done

# restore
for index in "${!names[@]}"
do
    declare "${names[index]}"="${values[index]}"
done

他と衝突する可能性が低い「var」、「index」、「names」、および「values」の代わりに変数名を使用します。変数を強制的にローカルにするため、内部関数exportの代わりに使用しますが、変数はエクスポートされ、望ましくない結果になる場合とそうでない場合があります。declaredeclare

推奨事項: 混乱を置き換えるか、使用するグローバルを減らすか、別の言語を使用してください。

それ以外の場合は、上で概説したことを試して、自分のコードでそれらのいずれかが機能するかどうかを確認してください。

于 2012-06-11T19:18:33.807 に答える