38

bashで連想配列を作成する方法を徹底的に探した結果、それでdeclare -A arrayうまくいくことがわかりました。しかし、問題は、それはbashバージョン4専用であり、サーバーがシステムに持っているbashバージョンは3.2.16であるということです。

bash 3である種の連想配列のようなハックをどのように達成できますか?値は次のようなスクリプトに渡されます

ARG=array[key];

./script.sh ${ARG}

編集:私はこれをawkまたは他のツールで実行できることを知っていますが、解決しようとしているシナリオには厳密なbashが必要です。

4

5 に答える 5

34

Bash 3には連想配列がないため、目的のために他の言語機能を使用する必要があります。bash 4の下でも、あなたが書いたコードはあなたが主張することをしないことに注意してください。連想配列の場合は何にも展開されない./script.sh ${ARG}ため、連想配列を子スクリプトに渡しません。連想配列を子プロセスに渡すことはできません。とにかくそれをエンコードする必要があります。${ARG}ARG

親スクリプトと子スクリプトの間で引数を渡すプロトコルを定義する必要があります。一般的な方法は、の形式で引数を渡すことkey=valueです。=これは、文字がキーに表示されないことを前提としています。

また、親スクリプトと子スクリプトで連想配列を表す方法を理解する必要があります。同じ表現を使用する必要はありません。

連想配列を表す一般的な方法は、要素ごとに個別の変数を使用し、共通の名前付けプレフィックスを付けることです。これには、キー名がASCII文字(いずれの場合も)、数字、およびアンダースコアのみで構成されている必要があります。たとえば、の代わりに${myarray[key]}、と記述し${myarray__key}ます。キーが実行時に決定される場合は、最初に拡張のラウンドが必要です。代わりに${myarray[$key]}、次のように記述します。

n=myarray__${key}; echo ${!n}

割り当てには、を使用しますprintf -v。指定された値を使用するための%sフォーマットに注意してください。フォーマットとして扱われ、printf拡張を実行するため、printf書き込まないでください。printf -v "myarray__${key}" %s "$value"$value%

printf -v "myarray__${key}" %s "$value"

このように表された連想配列をkey=value引数表現で子プロセスに渡す必要がある場合${!myarray__*}は、名前が。で始まるすべての変数を列挙するために使用できますmyarray__

args=()
for k in ${!myarray__*}; do
  n=$k
  args+=("$k=${!n}")
done

子プロセスで、フォームの引数をkey=value接頭辞付きの変数に変換するには、次のようにします。

for x; do
  if [[ $x != *=* ]]; then echo 1>&2 "KEY=VALUE expected, but got $x"; exit 120; fi
  printf -v "myarray__${x%%=*}" %s "${x#*=}"
done

ちなみに、これがあなたに必要なものだと確信していますか?別のbashスクリプトからbashスクリプトを呼び出す代わりに、代わりにサブシェルで子スクリプトを実行することをお勧めします。そうすれば、親のすべての変数から継承します。

于 2012-08-02T11:55:50.750 に答える
11

パラメータ拡張を使用したbash3以前の連想配列に関する別の投稿/説明は次のとおりです:
https ://stackoverflow.com/a/4444841

Gillesの方法には、if区切り文字の問題をキャッチしたり、奇数ボールの入力をサニタイズしたりするための優れたステートメントがあります。それを使用してください。

パラメータ拡張にある程度精通している場合:
http ://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

シナリオで使用するには[前述のとおり:スクリプトに送信]:スクリプト1: sending_array.sh

# A pretend Python dictionary with bash 3 
ARRAY=( "cow:moo"
        "dinosaur:roar"
        "bird:chirp"
        "bash:rock" )

bash ./receive_arr.sh "${ARRAY[@]}"

スクリプト2:receive_arr.sh

argAry1=("$@")

function process_arr () {
    declare -a hash=("${!1}")
    for animal in "${hash[@]}"; do
        echo "Key: ${animal%%:*}"
        echo "Value: ${animal#*:}"
    done
}

process_arr argAry1[@]

exit 0

方法2、2番目のスクリプトを調達する:スクリプト1: sending_array.sh

source ./receive_arr.sh
# A pretend Python dictionary with bash 3 
ARRAY=( "cow:moo"
        "dinosaur:roar"
        "bird:chirp"
        "bash:rock" )

process_arr ARRAY[@]

スクリプト2:receive_arr.sh

function process_arr () {
    declare -a hash=("${!1}")
    for animal in "${hash[@]}"; do
        echo "Key: ${animal%%:*}"
        echo "Value: ${animal#*:}"
    done
}

参照:
bashのパラメーターとして配列を渡す

于 2013-02-23T02:48:43.960 に答える
6

多くの変数を処理したくない場合、またはキーが単に無効な変数識別子であり、配列の項目が256未満であることが保証されている場合は、関数の戻り値を悪用する可能性があります。このソリューションでは、値が変数としてすぐに利用できるため、サブシェルも必要ありません。また、パフォーマンスが低下するような反復も必要ありません。また、Bash 4バージョンとほぼ同じように、非常に読みやすくなっています。

最も基本的なバージョンは次のとおりです。

hash_index() {
    case $1 in
        'foo') return 0;;
        'bar') return 1;;
        'baz') return 2;;
    esac
}

hash_vals=("foo_val"
           "bar_val"
           "baz_val");

hash_index "foo"
echo ${hash_vals[$?]}

この回答の詳細とバリエーション

于 2014-03-03T16:06:46.847 に答える
2

キーと値のペアをファイルに書き込んでから、キーごとにgrepを実行できます。次のようなパターンを使用する場合

key=value

その後、これをかなり安全にするegrepことができます。^key=

値を「上書き」するには、ファイルの最後に新しい値を追加し、を使用tail -1しての最後の結果だけを取得します。egrep

または、配列の値として使用してこの情報を通常の配列に入れkey=value、配列を反復処理して値を見つけることもできます。

于 2012-08-02T11:45:26.310 に答える
2

これは途方もなく簡単であることがわかりました。連想配列の束を使用するbash4スクリプトをbash3に変換する必要がありました。これら2つのヘルパー関数がすべてを実行しました。

array_exp() {
    exp=${@//[/__}
    eval "${exp//]}"
}

array_clear() {
    unset $(array_exp "echo \${!$1__*}")
}

これが実際に機能することに驚いていますが、それがbashの美しさです。例えば

((all[ping_lo] += counts[ping_lo]))

になります

array_exp '((all[ping_lo] += counts[ping_lo]))'

またはこの印刷ステートメント:

printf "%3d" ${counts[ping_lo]} >> $return

になります

array_exp 'printf "%3d" ${counts[ping_lo]}' >> $return

変更される唯一の構文はクリアです。これ:

counts=()

になります

array_clear counts

そして、あなたは設定されています。array_expに「=()」のような式を認識し、それらをarray_clear式として書き直すことで処理するように簡単に指示できますが、私は上記の2つの関数の単純さを好みます。

于 2015-04-01T03:24:27.717 に答える