我有一个数组
declare -a arr0=("'1 2 3'" "'4 5 6'")
和一个变量
x=0
然后我用数组的名称创建新变量
tmp="arr$x"
我希望能够像这样扩展arr0
这个变量的内容tmp
newArr=( "${!tmp}" )
newArr
并像普通数组一样使用,例如使用索引等。
但当我现在尝试打印它时,它看起来像这样:
$ echo ${newArr[@]}
'1 2 3'
仅存储第一个元素,我不知道如何修复它。
newArr
我也尝试过这样创建
newArr=( "${!tmp[@]}" )
但更糟糕的是——只打印了 0。
$ echo ${newArr[@]}
0
那么,您知道如果数组的名称存储在其他变量中,如何使用数组吗?
答案1
这是可能的评估:
$ declare -a array=( 1 2 3 4 )
$ echo "${array[@]}"
1 2 3 4
$ p=ay
$ tmp=arr$p
$ echo "$tmp"
array
$ echo "\${${tmp}[@]}"
${array[@]}
$ echo "newarray=(\"\${${tmp}[@]}\")"
newarray=("${array[@]}")
$ eval "newarray=(\"\${${tmp}[@]}\")"
$ echo "${newarray[@]}"
1 2 3 4
$
以 echo 开头的命令仅供参考,eval 是危险的。
请注意,上面的内容不保留稀疏数组的数组索引。
答案2
间接扩展有一些例外,并且使用 !数组中是例外之一。
来自 man bash:
如果参数的第一个字符是感叹号 (!),则引入一级变量间接寻址。 Bash 使用由参数的其余部分形成的变量的值作为变量的名称;然后扩展该变量,并在其余替换中使用该值,而不是参数本身的值。这称为间接扩展。
例外情况是下面描述的 ${!prefix*} 和 ${!name[@]} 的扩展。 ${!prefix*} 匹配前缀的名称。扩展为名称以前缀开头的变量名称,并以 IFS 特殊变量的第一个字符分隔。
如中所述BASH 常见问题解答06,一种解决方法如下:
arrA=("AA" "2" "4")
echo -e "array arrA contains: \c" && declare -p arrA
ref=arrA;
tmp=${ref}[@] #this can be adjusted to [1] , [2] etc to refer to particular array items
echo "Indirect Expansion Printing: ${!tmp}"
#Output
array arrA contains: declare -a arrA='([0]="AA" [1]="2" [2]="4")'
Indirect Expansion Printing: AA 2 4
答案3
bash
4.3 添加了对类似 namerefs 的支持ksh93
。
所以在 bash-4.3 或更高版本中你可以这样做:
a0[5]=whatever
x=0
typeset -n var="a$x"
printf '%s\n' "${var[5]}"
但请注意,这是一个参考(指针,而不是副本)指向变量姓名,而不是变量(当您在不同上下文中有多个同名变量(例如函数中的局部变量)时,差异很重要。
bash
复制ksh
数组及其笨拙的设计。复制数组bash
很困难,您可以使用辅助函数,例如:
copy_array() { # Args: <src_array_name> <dst_array_name>
eval '
local i
'"$2"'=()
for i in "${!'"$1"'[@]}"; do
'"$2"'[$i]=${'"$1"'[$i]}
done'
}
例如用作:
$ a0[5]=123
$ x=0
$ copy_array "a$x" var
$ typeset -p var
declare -a var=([5]="123")
ksh
(以及bash
复制的ksh
)是数组所在的唯一 shell疏(或者是键仅限于正整数的关联数组)(也是索引从 0 而不是 1 开始的唯一数组,或者不$array
直观地不扩展到元素而是索引 0 的元素)。使用其他 shell 就容易多了。
rc
:array_copy = $array
fish
:set array_copy = $array
csh
:set array_copy = ($array:q)
zsh
或者yash
:array_copy=("${array[@]}"}
对于间接复制(其中$var
包含源数组名称):
rc
:eval array_copy = '$'$var
fish
:eval set array_copy \$$var
csh
:eval "set array_copy = (\$${var}:q)"
zsh
:array_copy=("${(@P)var}")
yash
(或者zsh
):eval 'array_copy=("${'"$var"'[@]}")'