Bashでネストされたforループを使用する方法がわかりません。次のコードをネストされたforループに置き換えることはできますか?
~/
❯ cat sequential.sh
a=(1 2)
b=(3 4)
c=(5 6)
for e in "${a[@]}"
do
echo $e
done
for e in "${b[@]}"
do
echo $e
done
for e in "${c[@]}"
do
echo $e
done
✦ ~/
❯ bash sequential.sh
1
2
3
4
5
6
答え1
ループに関連付けられている「ネスト」とは、通常、1つのループを別のループ内に配置して、内部ループの各繰り返しセットが外部ループの各繰り返しに対して実行されることを意味します。
for letter in a b c; do
for digit in 1 2 3; do
printf 'Letter = %s\tDigit = %s\n' "$letter" "$digit"
done
done
...出力
Letter = a Digit = 1
Letter = a Digit = 2
Letter = a Digit = 3
Letter = b Digit = 1
Letter = b Digit = 2
Letter = b Digit = 3
Letter = c Digit = 1
Letter = c Digit = 2
Letter = c Digit = 3
しかし、あなたの質問によると、まだ同じ出力が欲しいと仮定すると、入れ子にしたくないようです。代わりにあなたが望む結合する3つの別々のループを1つのループにまとめます。
これは、ループヘッダーに配列拡張を1つずつ追加して、繰り返すより大きな文字列セットを生成することによって行われます。
a=(1 2)
b=(3 4)
c=(5 6)
for item in "${a[@]}" "${b[@]}" "${c[@]}"
do
printf 'item is "%s"\n' "$item"
done
これは、3つの小さな配列から別々の要素配列を作成し、より大きな配列を繰り返すのと同じ効果を持ちます。
a=(1 2)
b=(3 4)
c=(5 6)
combined=( "${a[@]}" "${b[@]}" "${c[@]}" )
# the above has the effect of setting the combined array as
# combined=( 1 2 3 4 5 6 )
for item in "${combined[@]}"; do
printf 'item is "%s"\n' "$item"
done
または、より短い位置引数のリストを使用します。
a=(1 2)
b=(3 4)
c=(5 6)
set -- "${a[@]}" "${b[@]}" "${c[@]}"
for item do
printf 'item is "%s"\n' "$item"
done
これは、ネストではなく、配列要素の3つの別々のセットをより大きなセットに結合することです。
printf
必要なものが最小限のコードで3つの配列の要素を出力することであれば、すべてのパラメータが出力されるまでフォーマット文字列がすべてのパラメータに順次適用されるという事実を使用できます。
a=(1 2)
b=(3 4)
c=(5 6)
printf 'item is "%s"\n' "${a[@]}" "${b[@]}" "${c[@]}"
もう一つの方法は少し厄介ですがするネストされたループの場合、実際の配列を繰り返し、各配列を順番に処理します。bash
シェルでは、ループを介してこれを行うことができます。名前名前参照変数を持つ配列:
a=(1 2)
b=(3 4)
c=(5 6)
for arrayname in a b c; do
declare -n array="$arrayname"
for item in "${array[@]}"; do
printf 'item is "%s" (from original array "%s")\n' "$item" "$arrayname"
done
done
ここでは、declare -n
変数がarray
現在の名前を持つすべての変数のように動作する必要があるとしばしば言います。arrayname
それからarray
それを配列のように使います。これは、拡張値が$arrayname
配列の名前であるために機能します。
これはやや珍しいプログラムですが、うまくbash
いきます。また、別の配列処理関数を導入してコードをより複雑にすることもできます(この特別な場合は、このコードを書くのに適した方法ではありません。単一のステートメントを使用し、printf
ループをまったく使用しないことをお勧めします)。 :
a=(1 2)
b=(3 4)
c=(5 6)
process_array () {
local -n array="$1"
for item in "${array[@]}"; do
printf 'item is "%s" (from original array "%s")\n' "$item" "$arrayname"
done
}
for arrayname in a b c; do
process_array "$arrayname"
done
これは「関数に配列を渡す」です(実際には、変数を参照するローカル名を持つ関数の配列名として使用される変数名を渡します)。
これにはいくつかの制限があります。たとえば、process_array
名前参照変数を使用して他の関数を呼び出すことはできませんarray
。また、見ることができますbash シェル関数には循環名参照がありますが、ksh にはありません。
答え2
✦ ~/
❯ cat nested.sh
a=(1 2)
b=(3 4)
c=(5 6)
for arr in "${a[@]}" "${b[@]}" "${c[@]}"
do
for e in "${arr[@]}"
do
echo $e
done
done
✦ ~/
❯ bash nested.sh
1
2
3
4
5
6
✦ ~/
❯