Bashの配列名に変数を持つ配列に値を追加するには?

Bashの配列名に変数を持つ配列に値を追加するには?

私のスクリプトにはグループ名のリストを含む配列があります。このリストには固定数の要素はありません。

GROUPS=(group1 group2 group3)

このグループセットの各要素には、不明な数の値がある可能性があります。名前に変数を含む配列セットを動的に生成します。ここで、VARIABLE はグループ名です。

for VARIABLE in "${GROUPS[@]}"
do
  declare -a ARRAY_${VARIABLE}
done

一連の値を繰り返し、条件が満たされたら、その値が属する配列に新しい要素として追加したいと思います。

for (( VALUES=1; VALUES<=10; VALUES++ ));
do 
  if the VALUE belongs to GROUPx assign it to the array for GROUPx 
    ARRAY_$VARIABLE+=("$VALUES")
  fi
done

これは、グループに属する値を含む配列で終わる必要があります。つまり:

ARRAY_group1= 1 2 5 9 10
ARRAY_group2= 3 7 
ARRAY_group3= 4 6 8

ただし、予期しないトークン "$ VALUES"の近くでbash:構文エラーが発生し続けます。 ARRAYという配列に割り当てると、完全に機能しますが、動的に生成する必要がある不明な数の配列にスクリプトの値を割り当てる必要があります。

名前に関連付けられた変数を含む文字列に値を追加してから、sedを使用して個々の値を選択できますが、その式の正しい構文も見つかりません。

let TEST_$VARIABLE="$TEST_$VARIABLE:$VALUES"
let TEST_$VARIABLE="${TEST_$VARIABLE}:$VALUES"
let TEST_$VARIABLE="$((TEST_$VARIABLE)):$VALUES"
let TEST_$VARIABLE="$((TEST_$VARIABLE))" ":$VALUES"

いくつかの他の方法を試しましたが、すべて同じ問題がありました。 bashは実際には名前に変数を使用するのが好きではありませんが、動的に生成する必要があるため、名前に変数を含める必要があります。

私はいくつかの異なる方法を試しましたが、すべての構文エラーと誤った代替エラーを避けるために、bashが名前に変数を含む変数を確実に参照する方法を知っている場合は本当に感謝します。

Tldr: bash が ARRAY[@] を処理するのと同じ方法で、 bash が ARRAY_$VARIABLE[@] を処理できるようにするいくつかの構文はありますか?

答え1

名前参照

私はnamerefがあなたが望むものだと思います。

name=foo
declare -a array_$name
declare -n target=array_$name
for x in asdf 'white space' ; do target+=("$x"); done 
declare -p array_$name

出力:

declare -a array_foo=([0]="asdf" [1]="white space")

評価する、宣言する、しよう

もう一つの悪い方法は、これらの値を使用またはeval設定することです。declare

eval$引用がトリッキーになるので、誤って値のsを拡張したくありません。

eval "array_$name+=(\"\$x\")"

declare配列に追加するのは少し難しいです。割り当てたいインデックスを知っていれば、とても簡単です。

declare "array_$name[$i]=$x"

(要素数を取得するには、array_$namenamerefまたはもう一度必要なようですeval。)

あなたはここにlet少し似ていると述べましたが、declare算術式の場合、一般的なケースには適していません。

name=a; 
let "test_$name=12+34"        # sets test_a to 46
let "test_$name=foo"          # reads the _value_ of variable foo!
let "test_$name=foo bar"      # this is an error.

代替データ構造

または、各値が1つしかない場合は、データ構造を反転して各値のグループIDを単一の配列に格納します。

for (( val=1; val <= 10; val++ )); do
     groupid=$(find_groupid "$val")
     variables[$val]=$groupid
done

その後、配列全体を繰り返し、興味のないグループを無視します。

または、値にスペースが含まれていない場合は、文字列を内部配列として使用してください。繰り返すには、次の手順を実行します。

for group in "${groups[@]}"; do 
    for item in $group; do       # no quotes here, we want wordsplitting
        ...

(または連想配列を使用してグループ名を保存します。)

関連情報