bash中的关联数组名称数组

Myc*_*cah 5 arrays bash shell

我正在尝试使用bash中的数组来管理关联数组列表,而我似乎无法找到哪些不正确.

我正在做的事情:

array=(a b c d)

for i in ${array[@]}; do
    declare -A $i
done

a[key]=avalue
b[key]=bvalue
c[key]=cvalue
d[key]=dvalue
Run Code Online (Sandbox Code Playgroud)

这一切似乎工作正常,因为我可以手动返回值通过引用${a[key]}就好了.

但是,当我试图迭代使用array变量时,它并没有真正给我我期望的东西.

for index in ${array[@]}; do
  echo ${index[key]}
done
Run Code Online (Sandbox Code Playgroud)

回来就像我要跑的一样

for index in ${array[@]}; do
  echo $index
done
Run Code Online (Sandbox Code Playgroud)

我觉得我错过了一些简单的东西,但寻找答案并没有找到任何解决方案.任何援助将不胜感激.

ric*_*ici 7

这是一个解决方案,使用shell间接.这适用于bash支持关联数组的任何数组.间接必须包含整个引用,包括下标,这有点尴尬.

for index in "${array[@]}"; do
  indexkey=${index}[key]
  echo "${!indexkey}"
done
Run Code Online (Sandbox Code Playgroud)

使用现代bash(至少v4.3),您可以使用nameref声明,它创建别名.这样更方便,因为您可以使用具有相同别名的不同键:

for index in "${array[@]}"; do
  declare -n subarray=$index
  echo "${subarray[key]}"
done
Run Code Online (Sandbox Code Playgroud)

接近解释的东西.

正如Etan Reisner在评论中指出的那样,这个问题在Bash FAQ条目中有一定篇幅.但是,在我编写的那一天,该FAQ条目包含免责声明"检修此页面需要一些时间和工作",而且FAQ条目目前还不像人们所希望的那样清晰.所以这是我的简短摘要:

  1. declare(和其他相关的内置命令,其中包括export,local,和typeset)评估他们的论点.因此,您可以在declare语句中构建变量名称.

  2. 由于declare也可以用于赋值(只要使用相同的声明),就可以在declare语句中建立索引变量名.

  3. 如果您使用的是bash4.3或更高版本,则可以使用namerefs(typeset -ndeclare -n)来模拟数组值.这真的是你可以从bash函数返回一个数组的唯一方法,但它仍然有点尴尬,因为它要求函数的调用者提供一个带有数组名称的参数; 此外,它不是完全健壮的,因为名称将在函数的范围内使用,因此它可能被局部变量遮蔽.需要注意.

  4. 使用变量间接可能没有其他充分的理由.如果您发现自己需要它,请考虑是否可以采用不同的方式构建程序.您可以使用字符串连接折叠关联键.例如:

    my_array[${place}:${feature}]
    
    Run Code Online (Sandbox Code Playgroud)

    只要没有${place}包含冒号的值(当然,您可以使用不同的字符而不是冒号),它将工作.

  5. 小心钥匙.如果数组被声明为关联的,则通常或多或少地评估键,但如果它是普通的索引数组,则将键计算为算术表达式.结果是

    declare -A assoc
    declare -a indexed
    key=42
    # This assigns the element whose key is "key"
    assoc[key]=foo
    # This assigns the element whose key is 42
    indexed[key]=foo
    # If $key had not been defined, the above would have assigned
    # the element whose key was 0, without an error message
    
    Run Code Online (Sandbox Code Playgroud)