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

前端 未结 4 750
孤街浪徒
孤街浪徒 2021-01-14 05:09

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

var1=\"target\"
var2=\"arrayname\"
targetarrayname=( \"one\" \"two\" \"three\" )
b         


        
相关标签:
4条回答
  • 2021-01-14 05:50

    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.

    0 讨论(0)
  • 2021-01-14 05:55
    #!/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.

    0 讨论(0)
  • 2021-01-14 06:00

    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
    
    0 讨论(0)
  • 2021-01-14 06:03

    The declare command takes assignments as arguments, which are expanded before the declaration. Thus, you can introduce any level of indirection when declaring variables. The following works in Bash 3.2.

    $ array=myarray
    $ declare -a "$array+=(\"element 1\")"
    $ echo ${myarray[0]}
    element 1
    
    0 讨论(0)
提交回复
热议问题