環境変数に配列値を格納し、Bashスクリプトから呼び出す回避策

環境変数に配列値を格納し、Bashスクリプトから呼び出す回避策

「配列を環境変数として使用した後、Bashシェルスクリプトから呼び出すことはできますか?」という質問に対する回答を調べたところ、「正式に」サポートされていないと結論付けました(概要)。ここここ)。

しかし、私はこの作業を必ずしなければならず、「解決方法」を思い出したので、皆さんの意見を聞きたいと思います。

設定:ファイルに.profile次の変数を作成しました。

HOST_NAMES='server1 server2 server3'

次に、シェルスクリプトの冒頭に次のように書きました。

SRVR_ARRAY=($(echo $HOST_NAMES | awk '{for (i = 1; i <=NF; i++) print $i " "}'))

スクリプトの後半でいくつかのタスクを実行する必要があるときは、次のように呼び出しました。

for h in "${SRVR_ARRAY[@]}"; do
ping $h
done

効果がありました!今私はこれがBashシェルスクリプトjerry-rigginの最高のバージョンであると確信しています。しかし、誰かがこの使用法でどのようなリスクを見ることができるかを知りたかったのですか?

答え1

直面する可能性のある問題は、スプリットやワイルドカードなどの一般的な問題です。

文字列は別々の配列項目に分割され、グローバル文字(*?[])に似たすべての項目が一致するファイル名に展開されるため、スペースを含めることはできません。ホスト名は問題ではないかもしれませんが、通常はそうです。

これはよくある質問で、繰り返し議論されます。 シェル変数の拡張とglobと分割の影響 そして bash / POSIXシェルで変数を引用することを忘れてしまうセキュリティリスク


IFSこれらの問題を解決するには、a)スペース以外の項目を設定し、それを使用して文字列を区切り、b)を無効にする必要がありますset -f

これは|区切り文字として機能し、文字列を分割します。値に不要な文字を使用できます。\001$'\001'Bashでこれを生成するために使用される)などの一部の制御文字も使用できます。

#!/bin/bash
string='foo|bar'
IFS='|'; set -f
array=($string)        # split it

IFS='|'
string="${array[*]}"   # merge it back together

また、コメントで述べたように、変数にホスト名のみがあり、スペースに分割できる場合は、分割にawkは必要ありません。シェルは、配列に割り当てるかループを開始するときにこれを行います。

SRVR_ARRAY=( $HOST_NAMES )
for x in $HOST_NAMES ; do ...

HOST_NAMES(やはりグローバル文字を含めると問題が発生します。)

実際、これはあなたの例でも起こります。awk何かが印刷され、シェルがそれをキャプチャし、$()二重引用符内にないので、それを単語に分割し、単語を別々に配列に保存します。

答え2

declare -p環境変数に出力を保存できます。

array=(foo 'bar baz'); array[12]=sparse
export ARRAY_definition="$(declare -p array)"

次に、実行されたスクリプトで次の操作を行いますbash

eval "$ARRAY_definition"

evalと同じロケールdeclare(好ましくは同じバージョンbash)で実行することが重要です。

グローバルスコープで実行されない場合、配列はeval宣言されます。地元の

参照を使用すると、zsh危険な参照の使用を回避できますeval

export ARRAY_definition=${(j: :)${(q)array}}

輸入:

array=(${(Q)${(z)ARRAY_definition}})

rcesあるいは、このようなものを使用するか、デフォルトで配列のエクスポートをサポートするfishシェル(自己エンコードを使用)を使用することもできます。

関連情報