如何在BASH中追加数组的间接参数扩展?

时间:2019-07-10 06:54:51

标签: linux bash unix

我知道您可以像这样为数组创建indirect parameter expansion

var1="target"
var2="arrayname"
targetarrayname=( "one" "two" "three" )
builtarrayname="${var1}${var2}[@]"
echo ${!builtarrayname} # prints "one two three"

但是我不知道如何添加到此间接引用,就像我通常直接使用targetarrayname+=('foo')一样。

我尝试过:

!builtarrayname+=('foo') # gives "Syntax error near unexpected token `'foo''"

和其他一些随机分类的尝试,基本上是对此的变体。

我的预期输出是让targetarrayname包含one two three foo,并通过间接参数扩展做到这一点。 这可能吗?

4 个答案:

答案 0 :(得分:3)

与Bash 3.2兼容

它避免了substantial security bugs通过printf %q运行所有值,以确保在将它们替换为eval内容之前可以安全地对其进行转义。

#!/bin/bash

appendToArray() {
  local _targetArrayName _argumentData _cmd
  _targetArrayName=$1; shift || return
  printf -v _argumentData '%q ' "$@"
  printf -v _cmd '%q+=( %s )' "$_targetArrayName" "$_argumentData"
  eval "$_cmd"
}

target=( "first item" "second item" )
appendToArray target "third item" "fourth item"
declare -p target

...正确发出作为输出:

declare -a target=([0]="first item" [1]="second item" [2]="third item" [3]="fourth item")

仅适用于Bash 4.3 +

#!/bin/bash

appendToArray() {
  declare -n _targetArray=$1; shift
  _targetArray+=( "$@" )
}

target=( "first item" "second item" )
appendToArray target "third item" "fourth item"
declare -p target

...具有相同的输出,所用的代码更少(也更简单)。

答案 1 :(得分:1)

#!/bin/bash

var1="target"
var2="arrayname"
targetarrayname=( "one" "two" "three" )
builtarrayname="${var1}${var2}[@]"
echo ${!builtarrayname} # prints "one two three"

eval "${builtarrayname:0:-3}+=( 'foo' )"

echo ${!builtarrayname} # prints "one two three foo"

请注意,尽管eval可能被认为是邪恶的:p 您需要确保只对eval语句进行了清理,以免意外执行代码。

编辑:

:0:-3中的eval "${builtarrayname:0:-3}+=( 'foo' )"[@]包含的文字字符串中删除了$builtarrayname。由于数组的分配仅使用变量名,因此我们必须将其删除。 (read more here to see how string manipulation in variables work

不,我认为没有评估就无法完成,因为这是在分配发生之前解析分配左侧的方式(请参见this nice answer for more info on eval

答案 2 :(得分:0)

您可以使用printf

arrayname=()
arrayvariable=arrayname

printf -v $arrayvariable[1] "test"
echo "${arrayname[1]}"

要填充整个数组,可以使用for循环

arrayname=()
arrayvariable=arrayname

for i in {0..5}; {
    item="$arrayvariable[$i]"
    printf -v $item "test$i"
    echo "${!item}"
}

请注意,printf命令中的var name不需要用引号引起来,因为var name不能有空格,如果尝试在名称中添加var并带有空格,则会出现此错误

$ printf -v 'test 1' 'sef'
bash: printf: `test 1': not a valid identifier

答案 3 :(得分:0)

declare命令将分配作为参数,在声明之前将其扩展。因此,在声明变量时可以引入任何间接级别。以下内容可在Bash 3.2中使用。

$ array=myarray
$ declare -a "$array+=(\"element 1\")"
$ echo ${myarray[0]}
element 1