在Bash Script中给定一组数组的变量名,循环遍历数组元素

时间:2017-03-29 11:07:39

标签: bash shell

我有一个包含类别名称的数组

categories=( categoryA categoryB categoryC )

每个类别都包含多个产品,这些产品存储在不同的数组中。

categoryA=( productA1 productA2 productA3 )
categoryB=( productB1 productB2 productB3 )
categoryC=( productC1 productC2 productC3 )

我想循环所有产品,所以我写了这段代码:

categories=( categoryA categoryB categoryC )

categoryA=( productA1 productA2 productA3 )
categoryB=( productB1 productB2 productB3 )
categoryC=( productC1 productC2 productC3 )

for category_name in "${categories[@]}"
do
    echo $category_name

    category=${!category_name}
    for product in "${category[@]}" 
    do
        echo -e '\t' $product
    done

    echo -e '\n'

done

我希望输出为:

CategoryA
    ProductA1  
    ProductA2
    ProductA3

CategoryB
    ProductB1  
    ProductB2
    ProductB3

CategoryC
    ProductC1  
    ProductC2
    ProductC3

但不幸的是,输出是

CategoryA
    ProductA1  

CategoryB
    ProductB1  

CategoryC
    ProductC1  

如何解决这个问题?

3 个答案:

答案 0 :(得分:1)

在这种情况下,绝对要 NOT 使用eval,只需使用declare动态创建变量,

只需替换

category=${!category_name}

在你的原始答案中

declare -n category="${category_name}"

上述declare语法将为变量category创建category_name的引用,可以进一步访问该变量以便作为数组进行扩展。

declare -nBash 4.3-alpha

中引入的相对较新的语法

答案 1 :(得分:1)

如果Inian's answer不适合您,因为您使用的是早于4.3的bash版本(引入了对nameref变量的支持),您可以使用以下解决方案:

categories=( categoryA categoryB categoryC )

categoryA=( productA1 productA2 productA3 )
categoryB=( productB1 productB2 productB3 )
categoryC=( productC1 productC2 productC3 )

for category_name in "${categories[@]}"
do
    echo $category_name


    array_declaration="$(declare -p $category_name)"
    # "$array_declaration" expands to the command that can be (safely)
    # evaluated to recreate the $category_name variable 

    # change the variable name in the array declaration and eval it
    eval "${array_declaration/#declare -a "$category_name"=/declare -a category=}"

    for product in "${category[@]}"
    do
        echo -e '\t' $product
    done

    echo -e '\n'

done

请注意,上述代码中对eval的依赖应该是安全的,因为declare -p的输出已正确引用。

答案 2 :(得分:0)

我已经找到了解决方案,

而不是category=${!category_name}
我可以评估数组eval category=\( \${${category_name}[@]} \)

对于那些感兴趣的人,这里是:

for category_name in "${categories[@]}"
do
    echo $category_name

    eval category=\( \${${category_name}[@]} \)
    for product in "${category[@]}" 
    do
        echo -e '\t' $product
    done

    echo -e '\n'

done

对于遇到同样挑战的人,以及任何有更优雅解决方案或任何反对意见的人,我会留下问题和答案

更新:出于安全考虑,请检查Inian的响应,如果您使用Bash< 4.3和我一样,检查莱昂的回应是另类