両方の配列の同じインデックスの値を同時にエコー

両方の配列の同じインデックスの値を同時にエコー

Bashスクリプトで同時に処理したい2つの配列があります。最初の配列には一種のラベルが含まれています。 2番目の配列には、次の値が含まれます。

LABELS=(label1 label2 label3 labe4 )
VALUES=(91 18 7 4)

必要なもの:次のように、LABELS配列のインデックス項目とVALUES配列の対応する項目値の前にエコーするループ。

label1 91
label2 18
label3 7
label4 4

入れ子になったループがうまくいかないと思います。以下で試しましたが、構文によると機能しません。

for label in {LABELS[@]} && value in {VALUES[@]}
do
    echo ${label} ${value}
done

答え1

数値インデックスを使用し、インデックスとして配列要素を参照してください。

labels=(label1 label2 label3 label4)
values=(91 18 7 4)


for((i=0; i<"${#labels[@]}"; i++ )); do
  printf '%s: %s\n' "${labels[i]}" "${values[i]}"
done

または、比較的新しい(> =バージョン4)bashまたは関連配列をサポートする別のシェルを使用している場合は、単一の配列を使用できます。

declare -A values=( ["label1"]=91 ["label2"]=18 \
                    ["label3"]=7 ["label4"]=4 )

for label in "${!values[@]}"; do
  printf '%s: %s\n' "$label" "${values[$label]}"
done

シェルスクリプトでローカル変数に大文字を使用するのは悪い習慣であり、グローバル環境変数は慣例的に大文字で表示されるため、スクリプトで大文字を使用すると変数名の競合が発生する可能性があるため、変数名を小文字に変更しました.

答え2

両方の配列はまったく同じインデックス(0、1、2、3)を持つため、配列の1つの${!array[@]}インデックス(キーとも呼ばれます)を繰り返し、そのイテレータを使用して両方の配列の値にアクセスできます。

これは、「インデックス配列」(すなわち整数インデックス)および「関連配列」(文字列インデックス)に対して機能する。

例えば

LABELS=(label1 label2 label3 labe4 )
VALUES=(91 18 7 4)

for i in "${!LABELS[@]}"; do
  echo "${LABELS[i]}" "${VALUES[i]}"
done

出力:

label1 91
label2 18
label3 7
labe4 4

ところで、このようなループを使用して連想配列を埋めることもできます。これは、手動で定義された2つの配列など、キーと値を同時に読み取れない場合に便利です。

LABELS=(label1 label2 label3 labe4)
VALUES=(91 18 7 4)

declare -A LV # declare LV to be an associative array

for i in "${!LABELS[@]}"; do
  LV["${LABELS[$i]}"]="${VALUES[$i]}";
done

declare -p LV

出力:

declare -A LV=([labe4]="4" [label3]="7" [label2]="18" [label1]="91" )

これで、スクリプトは$LV連想配列を使用してキーの値に直接アクセスできます。

$ echo "${LV[label1]}"
91

@terdonや@NickMatteoの答え(0から配列の長さまで繰り返す)などのCスタイルのforループを使用することもできますが、これは配列インデックスが数字で連続的で配列にギャップがない場合にのみ機能します(未定義のインデックス)。です。

ほとんどの場合、これは大丈夫です。なぜなら、配列はしばしばはい連続したインデックス番号として定義されますが、他の場合は期待どおりに機能しません。たとえば、$arrayインデックスが1、3、5、7、11、13、17、7${#array[@]}に対して定義されている場合、返され、これらのループが開始されます。 0から繰り返しを開始します。 .6(または代わり<=<テスト条件として使用する場合は0..7)配列の実際のインデックスリストの代わりに。

たとえば、

$ for i in 1 3 5 7 11 13 17 ; do let array[$i]=$i*$i ; done

$ declare -p array
declare -a array=([1]="1" [3]="9" [5]="25" [7]="49" [11]="121" [13]="169" [17]="289")

$ echo "${#array[@]}"
7

$ for ((i=0; i<"${#array[@]}"; i++)); do echo $i: "${array[$i]}" ; done
0: 
1: 1
2: 
3: 9
4: 
5: 25
6: 

$ echo "${!array[@]}"
1 3 5 7 11 13 17

$ for i in "${!array[@]}"; do echo $i: "${array[$i]}"; done
1: 1
3: 9
5: 25
7: 49
11: 121
13: 169
17: 289

答え3

インデックスを繰り返すだけです。例えば

for (( i = 0; i < "${#LABELS[@]}"; i++ ))
do echo "${LABELS[$i]} ${VALUES[$i]}"
done

また、次のようなより多くの書式コントロールをecho使用することもできます。printf

printf '%6s: %3d\n' "${LABELS[$i]}" "${VALUES[$i]}"

最大6文字、最大3桁の数字でラベルを配置します。

答え4

その必要はなく、配列圧縮演算子を使用している人bashのためにzsh${arrayA:^arrayB}

$ labels=(label1 label2 label3 labe4 )
$ values=(91 18 7 4)
$ for k v (${labels:^values}) print -r -- "$k => $v"
label1 => 91
label2 => 18
label3 => 7
labe4 => 4

ループが必要なくても:

$ print -raC2 -- ${labels:^values}
label1  91
label2  18
label3  7
labe4   4

print彼らは柱にr十字架の印を作りました。a2 C

$ printf '%6s => %d\n' ${labels:^values}
label1 => 91
label2 => 18
label3 => 7
 labe4 => 4

しかし、ここでは次のようにすることもできます。

$ print -rC2 -- $labels $values
label1  91
label2  18
label3  7
labe4   4

print両方のアレイについて、olumnrについて説明します2 C(ここでは省略-a)。

これら2つの配列を使用して連想配列を作成できることに注意してください(ここでは意味があるように聞こえます)。

typeset -A assoc
assoc=( ${labels:^values} )

ラベルまたは値に空の文字列を含めることができる場合は、次を使用することをお勧めします。

assoc=( "${(@)labels:^values}" )

それらを保護するために。

それから:

print -raC2 -- ${(kv)assoc}

便宜上、print k列を交差させるか、空のキー/値を残してください。vra2 C

print -raC2 -- "${(@kv)assoc}"

または:

for key value ("${(@kv)assoc}") print -r -- "$key => value"

または:

for key ("${(@k)assoc}") print -r -- "$key => $assoc[$key]"

ただし、連想配列項目が展開される順序は指定されません。

関連情報