How do you append to an indirect parameter expansion of an array in BASH?

六月ゝ 毕业季﹏ 提交于 2020-03-15 05:47:47

问题


I know you can create an indirect parameter expansion to an array like so:

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

But I can't figure out how to append to this indirect reference, as I normally would directly with targetarrayname+=('foo').

I've tried:

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

and some other random assorted attempts which are basically variations on this.

My intended output is to have targetarrayname contain one two three foo, and to have done so by indirect parameter expansion. Is this possible?


回答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"

Do note though that eval could be considered evil :p You need to be sure that you only have sanitized input to eval statements, to avoid the possibility of unintended code execution.

EDIT:

The :0:-3 in eval "${builtarrayname:0:-3}+=( 'foo' )" removes [@] from the literal string that $builtarrayname contains. Since assignment of arrays only use the variable name, we had to remove it. ( read more here to see how string manipulation in variables work )

and no, I don't think it can be done without eval, as that's how the left side of the assignment gets resolved before the assignment occurs (see this nice answer for more info on eval.




回答2:


With Bash 3.2 Compatibility

It avoids substantial security bugs to run all values through printf %q to ensure that they're safely escaped before substituting them into eval content.

#!/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

...correctly emits as output:

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

For Bash 4.3+ Only

#!/bin/bash

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

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

...has identical output, with much less (and much simpler) code.




回答3:


You can do it with printf

arrayname=()
arrayvariable=arrayname

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

To fill in whole array you can use a for loop

arrayname=()
arrayvariable=arrayname

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

Note that quotes are not necessary around var name in printf command because var name can't have spaces, if you try to add var with space in name it'll give you this error

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


来源:https://stackoverflow.com/questions/56964941/how-do-you-append-to-an-indirect-parameter-expansion-of-an-array-in-bash

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!