问题
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