如何从数组名称扩展数组内容?

如何从数组名称扩展数组内容?

我有一个数组

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

bash4.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或者yasharray_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"'[@]}")'

相关内容