稀疏数组

稀疏数组

Bash 手册页描述了使用 来返回名称为(间接级别)${!a}内容的变量的内容。a

我想知道如何使用它返回数组中的所有元素,即

a=(one two three)
echo ${a[*]}

回报

one two three

我想要:

b=a
echo ${!b[*]}

返回相同的。不幸的是,它没有,而是返回0

更新

鉴于答复,我现在意识到我的例子太简单了,因为当然,像这样:

b=("${a[@]}")

将会实现我所说的我需要的一切。

所以,这就是我的情况去做:

LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)

whichone=$1   # 'lys' or 'diaspar'

_LIST=LIST_$whichone
LIST=${!_LIST[*]}

当然,仔细阅读 Bash 手册页会发现这不会按预期工作,因为最后一行只是返回“数组”的索引$_LIST(根本不是数组)。

无论如何,以下内容应该可以完成工作(如所指出的):

LIST=($(eval echo \${$_LIST[*]}))

或...(我最终走的路线):

LIST_lys="lys1 lys2"
...
LIST=(${!_LIST})

当然,假设元素不包含空格。

答案1

我认为 bash 变量的间接引用的使用应该按字面意思对待。

例如。对于你原来的例子:

a=(one two three)
echo ${a[*]} # one two three
b=a
echo ${!b[*]} # this would not work, because this notation 
              # gives the indices of the variable b which
              # is a string in this case and could be thought
              # as a array that conatins only one element, so
              # we get 0 which means the first element
c='a[*]'
echo ${!c} # this will do exactly what you want in the first
           # place

对于最后一个真实场景,我相信下面的代码可以完成工作。

LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)

whichone=$1   # 'lys' or 'diaspar'

_LIST="LIST_$whichone"[*]
LIST=( "${!_LIST}" ) # Of course for indexed array only 
                     # and not a sparse one

最好使用"${var[@]}"避免混淆$IFS和 参数扩展的符号。这是最终的代码。

LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)

whichone=$1   # 'lys' or 'diaspar'

_LIST="LIST_$whichone"[@]
LIST=( "${!_LIST}" ) # Of course for indexed array only 
                     # and not a sparse one
                     # It is essential to have ${!_LIST} quoted

答案2

您需要显式复制元素。对于索引数组:

b=("${a[@]}")

对于关联数组(注意a是数组变量的名称,而不是其值为数组变量名称的变量):

typeset -A b
for k in "${!a[@]}"; do b[$k]=${a[$k]}; done

如果数组中有变量名称,则可以使用逐元素方法以及额外的步骤来检索键。

eval "keys=(\"\${!$name[@]}\")"
for k in "${keys[@]}"; do eval "b[\$k]=\${$name[\$k]}"; done

(警告,本文中的代码是直接在浏览器中输入的,未经测试。)

答案3

${!b[*]}扩展到 array 中使用的索引b

您想要的必须分两步完成,因此eval会有所帮助:eval echo \${$b[*]}。 (请注意,它\确保第一个$将通过第一步,即变量扩展,并且仅在第二步中通过 进行扩展eval。)

根据参数扩展,!两者都用于间接扩展 ( {!a})、匹配前缀的名称 ( ${!a*}) 和数组键列表 ( ${!a[*]})。由于数组键列表与预期的间接扩展+数组元素扩展具有相同的语法,因此不支持后者。

答案4

要间接访问数组,只需添加[@]到间接变量b=a[@]

如果设置了该变量:

a=(one two three)
printf '<%s> ' "${a[@]}"; echo

然后,这将起作用:

b="a[@]"
printf '<%s> ' "${!b}"

或者简单地:

echo "${!b}"

这样的数组可以复制如下:

newArr=( "${!b}" )

然后打印:

declare -p newArr

在一个脚本中:

#!/bin/bash
a=(one two three)
echo "original array"
printf '<%s> ' "${a[@]}"; echo

echo "Indirect array with variable b=a[@]"
b="a[@]"
printf '<%s> ' "${!b}"; echo

echo "New array copied in newArr, printed with declare"
newArr=( "${!b}" )
declare -p newArr

当然,以上所有操作都会复制一个非稀疏数组。所有索引都有值的一种。

稀疏数组

稀疏数组是一种可能包含未定义元素的数组。
例如a[8]=1234定义一个元素,而在bash中,0到7不存在。

要复制此类稀疏数组,请使用此方法

  1. 打印旧数组:

    $ oldarr[8]=1234
    $ declare -p oldarr
    declare -a oldarr=([8]="1234")
    
  2. 替换数组的名称并捕获字符串:

    $ str=$(declare -p oldarr | sed 's/oldarr=/newarr=/')
    
  3. 评估如此创建的字符串,新数组已被定义:

    $ eval "$str"
    $ declare -p newarr
    declare -a newarr=([8]="1234")
    

相关内容