如何使用包含数组名称的第二个变量引用现有的bash数组?

4

在发帖前搜索到的最相关和有用的问题:

如何迭代存储在变量中的Shell数组?

如何在Bash脚本中将参数名称用作变量?

如何使用间接引用迭代数组?

我的尝试并取得部分成功:

#!/bin/bash

declare -a large_furry_mammals
declare -a array_reference  
# I tried both declaring array_reference as an array and 
# not declaring it as an array.  no change in behavior.

large_furry_mammals=(horse zebra gorilla)


size=large
category=mammals

tmp="${size}_furry_${category}"
eval array_reference='$'$tmp

echo tmp=$tmp
echo array_reference[0]=${array_reference[0]}
echo array_reference[1]=${array_reference[1]}

输出

tmp=large_furry_mammals
array_reference[0]=horse
array_reference[1]=

期望结果

当我输出array_reference[1]时,我希望得到输出结果为斑马。

...但是我错过了一些细节...

为什么我不能访问索引数组中超出索引0的元素? 这表明array_reference实际上并没有被视为数组。

我不想复制数组。我想基于指向该数组的变量引用(将要成为)静态数组,即${size}_furry_${category} -> large_furry_mammals

我已经成功地使用我发布的链接来实现这里的一般思路,但前提是它不是一个数组。 当它是一个数组时,它对我来说有问题。

补充 2018年12月5日

在这种情况下,bash 4.3不可用。@benjamin的答案在4.3以下版本中有效。

我需要循环遍历生成的数组变量内容。我给出的哺乳动物的愚蠢示例只是为了描述这个概念。实际上,这周围有一个真实世界的案例。我有一组静态参考数组,并且将解析输入字符串以选择相关的数组,然后我将循环遍历所选的数组。我可以使用case语句,但对于超过100个参考数组来说,这将是直接但过于冗长的方法。

这个伪代码可能更好地说明了我的意图。

m1_array=(x a r d)
m2_array=(q 3 fg d)
m3_array=(c e p)

Based on some logic...select which array prefix you need.
x=m1

for each element in ${x}_array
do
   some-task
done

我正在测试@eduardo的解决方案,看看我是否可以调整他引用变量的方式来实现我的最终目标。
** 附录#2 2018年12月14日 **
解决方案
我找到了!在与@eduardo的示例一起工作时,我得出了以下结论:
#!/bin/bash

declare -a large_furry_mammals
#declare -a array_reference

large_furry_mammals=(horse zebra gorilla)


size=large
category=mammals

tmp="${size}_furry_${category}[@]"

for element in "${!tmp}"
do
    echo $element
done

这里是代码执行的样子。我们成功迭代了动态构建的字符串数组中的元素。
./example3b.sh

horse
zebra
gorilla

谢谢大家。


2
每当你想间接地做某事时,你应该首先尝试直接去做。无法将间接性添加到尚未工作的事物中。请参见此问题以了解如何复制数组。 - that other guy
2个回答

2
如果您使用的是Bash 4.3或更新版本,您可以使用namerefs:
large_furry_mammals=(horse zebra gorilla)
size=large
category=mammals
declare -n array_reference=${size}_furry_$category
printf '%s\n' "${array_reference[@]}"

输出结果

horse
zebra
gorilla

这是一个引用,因此在large_furry_mammalsarray_reference中进行更改都会反映出来:
$ array_reference[0]='donkey'
$ large_furry_mammals[3]='llama'
$ printf '%s\n' "${array_reference[@]}"
donkey
zebra
gorilla
llama
$ printf '%s\n' "${large_furry_mammals[@]}"
donkey
zebra
gorilla
llama

这个解决方案在bash 4.3下确实有效。我只能使用旧版本,但想承认它是一个可靠的解决方案。感谢您抽出时间来回答。 - Pytheas

1
declare -a large_furry_mammals
declare -a array_reference
large_furry_mammals=(horse zebra gorilla)

size=large
category=mammals

echo ${large_furry_mammals[@]}
tmp="${size}_furry_${category}"
array_reference=${tmp}"[1]"
eval ${array_reference}='bear'
echo tmp=$tmp
echo ${large_furry_mammals[@]}

array_reference 将是一个副本。如果您修改 array_reference[0]large_furry_mammals[0] 将不会改变。 - Benjamin W.
好的,已更新。请注意现在如何将斑马更改为熊,但您将看到我正在对数组项1进行评估,因此我需要花费更多时间来给出完整的示例。我现在必须离开,但至少它向您展示了一种作为指针工作的方法。 - Eduardo
我认为这将是我可以最适合我的用例的解决方案。现在看看它。在我以各种方式测试过之后,我会在一天左右更新。谢谢@Eduardo。 - Pytheas
这是一个有趣的练习,只是真的很烦人。我会看看今晚或明天是否尝试更干净的解决方案。 - Eduardo
1
@ Eduardo - 我使用了你的示例,并找到了解决方案。解决方案已添加到我的原始帖子中。简而言之:我需要在我的数组赋值语句中添加[@]。我的初始尝试包括构造没有方括号的数组名称,然后在尝试引用数组元素时在后端使用方括号。如果在初始赋值中包含[@],则数组间接引用有效。虽然您的示例与我所做的不是直接匹配,但它让我朝着正确的方向开始了。 - Pytheas
太好了,我一直非常忙,很高兴你自己找到了最终的解决方案。 - Eduardo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接