嵌套循环和数组

嵌套循环和数组

我不知道如何在 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

通过“嵌套”(与循环相关),通常意味着将一个循环放入另一个循环中,以便针对外循环的每次迭代执行内循环的每组迭代,如下所示

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

但是,在您的问题中,假设您仍然希望拥有相同的输出,那么您似乎不想进行任何嵌套。相反,你想要结合将三个单独的循环合并为一个循环。

只需将数组的扩展一个接一个地添加到循环头中即可完成此操作,以创建一组更大的要迭代的字符串:

a=(1 2)
b=(3 4)
c=(5 6)

for item in "${a[@]}" "${b[@]}" "${c[@]}"
do
    printf 'item is "%s"\n' "$item"
done

这与创建一个由三个较小数组中的元素组成的单独数组并迭代该较大数组具有相同的效果:

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

请注意,这不是嵌套,而是将三个独立的数组元素集组合成一个更大的集合。


如果我们想要做的只是使用最少量的代码输出三个数组的元素,我们可能需要使用以下事实:将printf格式字符串依次应用于所有参数,直到所有参数都已输出:

a=(1 2)
b=(3 4)
c=(5 6)

printf 'item is "%s"\n' "${a[@]}" "${b[@]}" "${c[@]}"

另一种方法来做到这一点,这有点尴尬,但涉及嵌套循环,就是循环遍历实际数组并依次处理每个数组。在bashshell 中,您可以通过循环来完成此操作名字具有名称引用变量的数组:

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 shell 函数中存在循环名称引用,但 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

✦ ~/

相关内容