Bash:配列への間接参照にアクセスする

Bash:配列への間接参照にアクセスする

私のスクリプトには、 "versions_"文字列で始まるさまざまなバリアント変数があります。たとえば、次のようになります。

versions_a=("1" "2")
versions_b=("3" "4")

次の変数を繰り返して基本配列にアクセスしたいと思います。

#!/usr/bin/env bash
versions_a=("1" "2")
versions_b=("3" "4")


for i in ${!versions_*}; do
    
    #Ideally if statement here if underlying array is empty, continue to next iteration

    echo "${i} contains ${i[*]}"
    versions=(${!i})
    echo "versions has ${versions[@]}"
   
    for x in "${versions[@]}"; do 
      echo ${x} #should print 1, then 2, then 3, then 4
    done
done

予想出力:

versions_a has 1 2
versions has 1 2
1
2
versions_b has 3 4
versions has 3 4
3
4

現在の出力:

versions_a contains versions_a
versions has 1
1
versions_b contains versions_b
versions has 3
3

答え1

最も簡単な方法は、ここでnamerefを使用することです(bash 4.3以降の仮定)。

#! /bin/bash -

versions_a=( 1 2 )
versions_b=( 3 4 )
versions_c=( -n '*' )

for varname in "${!versions_@}"; do
  typeset -n versions="$varname"

  IFS=,
  printf '%s\n' "$varname contains ${versions[*]}"

  for x in "${versions[@]}"; do
    printf '%s\n' "$x"
  done
done

これは作る:

versions_a contains 1,2
1
2
versions_b contains 3,4
3
4
versions_c contains -n,*
-n
*

また、パラメータ拡張は引用符で囲む必要があり、echo任意のデータを出力するために使用できないことを覚えておいてください。または"$*"の拡張は、 の"${array[*]}"現在の値によって異なります$IFS(ここでは に設定して説明します,)。

答え2

バラよりこの回答:

[@]難しいのは、間接的に渡す変数に配列要素(またはすべての要素)を含める必要があることです。

...または[*]それがあなたが望むものなら。このような:

#!/usr/bin/env bash
versions_a=("1" "2")
versions_b=("3" "4")
versions_c=()


for i in ${!versions_*}; do
    
    group=${i#*"_"} #removes the 'versions_'
    versions="${i}[@]"
    last_version=${!versions: -1}

    if [[ -z ${last_version} ]]; then
        echo "Empty, skipping."
        continue
    fi

    echo "${i} as ${group} has ${!versions}"
   
    for x in "${!versions}"; do 
      echo "${group} & ${x}"
    done
done

出力

versions_a as a has 1 2
a & 1
a & 2
versions_b as b has 3 4
b & 3
b & 4
Empty, skipping.

関連情報