我有三个关联数组:
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_obj
gopath
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
在bash
4.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}"
)
无论如何,在bash
and 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