bash中如何通过变量的值引用关联数组变量?

bash中如何通过变量的值引用关联数组变量?

我有三个关联数组:

declare -A start_obj end_obj gopath

start_obj['one']="start-obj-one"
start_obj['two']="start-obj-two"

end_obj['one']="end-obj-one"
end_obj['two']="end-obj-two"

gopath['start']="/path/to/start"
gopath['end']="/path/to/end"

我想通过数组的键来获取数组的键和值start_obj,代码如下:end_objgopath

for t in "${!gopath[@]}"
do
    current=$t"_obj"[@]
    cd ${gopath[$t]}
    for k in ${!current}
    do    
        printf  "[$t]key is : $k ; value is : ${current[$k]}\n"                                                           
    done
done

但是,这段代码的执行结果是:

[start]key is : start-obj-one ; value is : start_obj[@]
[start]key is : start-obj-two ; value is : start_obj[@]
[end]key is : end-obj-one ; value is : end_obj[@]
[end]key is : end-obj-two ; value is : end_obj[@]

我期望的结果是:

[start]key is : one ; value is : start-obj-one
[start]key is : two ; value is : start-obj-two
[end]key is : one ; value is : end-obj-one
[end]key is : two ; value is : end-obj-two

那么,我应该如何修改我的代码才能得到我期望的结果呢?

答案1

bash4.3 或更高版本中,您可以使用 nameref 变量:

for t in "${!gopath[@]}"; do
  (
    typeset -n current="${t}_obj"
    cd -P -- "${gopath[$t]}" || exit
    for k in "${!current[@]}"
    do    
      printf '%s\n' "[$t]key is: $k; value is: ${current[$k]}"
    done
  )
done

对于旧版本,您需要使用eval

for t in "${!gopath[@]}"; do
  (
    cd -P -- "${gopath[$t]}" || exit
    eval '
      for k in "${!'"$t"'_obj[@]}"
      do    
        printf "%s\n" "[$t]key is: $k; value is: ${'"$t"'_obj[$k]}"
      done
    '
  )
done

bash有一个变量间接运算符:${!varname},与运算符无关${!hash[@]}(实际上更接近 ksh93 中的相反内容${!varname}),但它不能与运算符组合${!hash[@]}varname=hash; for key in "${!!varname[@]}"...不起作用)。对于此处具有可用变量间接运算符的 shell(并且支持关联数组的时间更长),您可以查看zsh(using ${(P)varname}),它还允许您同时循环键和值:

typeset -A start_obj end_obj gopath
start_obj=(
  one  start-obj-one
  two  start-obj-two
)
end_obj=(
  one  end-obj-one
  two  end-obj-two
)
gopath=(
  start  /path/to/start
  end    /path/to/end
)
for t dir ("${(kv@)gopath}") (
  cd -P -- "$dir" || exit
  current=${t}_obj
  for key value ("${(kvP@)current}")
    printf '%s\n' "[$t]key is: $key; value is: $value}"
)

无论如何,在bashand zsh(以及ksh93引入关联数组并bash尝试复制的第一个 shell)中,关联数组被实现为哈希表,因此元素不以任何特定顺序存储,因此上面的代码将循环遍历它们以看似随机的顺序。

答案2

对于早期的 bash 版本,您可以使用以下命令执行此操作索引数组,但不是关联数组,使用变量间接寻址:

$ declare -p start_obj end_obj gopath
declare -A start_obj='([one]="start-obj-one" [two]="start-obj-two" )'
declare -A end_obj='([one]="end-obj-one" [two]="end-obj-two" )'
declare -A gopath='([start]="/path/to/start" [end]="/path/to/end" )'

$ for t in "${!gopath[@]}"; do tmp="${t}_obj[@]"; ary=( "${!tmp}" ); declare -p ary; done
declare -a ary='([0]="start-obj-one" [1]="start-obj-two")'
declare -a ary='([0]="end-obj-one" [1]="end-obj-two")'

请注意我们如何获得价值观但不是的关联数组。

有关详细信息,请参阅第 4 段https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion

相关内容