A confusion about ${array[*]} versus ${array[@]} in the context of a bash completion

前端 未结 2 598
情歌与酒
情歌与酒 2020-11-29 16:21

I\'m taking a stab at writing a bash completion for the first time, and I\'m a bit confused about about the two ways of dereferencing bash arrays (${array[@]} a

2条回答
  •  臣服心动
    2020-11-29 17:09

    Your title asks about ${array[@]} versus ${array[*]} but then you ask about $array[*] versus $array[@] which is a bit confusing. I'll answer both:

    When you quote an array variable and use @ as a subscript, each element of the array is expanded to its full content regardless of whitespace (actually, one of $IFS) that may be present within that content. When you use the asterisk (*) as the subscript (regardless of whether it's quoted or not) it may expand to new content created by breaking up each array element's content at $IFS.

    Here's the example script:

    #!/bin/sh
    
    myarray[0]="one"
    myarray[1]="two"
    myarray[3]="three four"
    
    echo "with quotes around myarray[*]"
    for x in "${myarray[*]}"; do
            echo "ARG[*]: '$x'"
    done
    
    echo "with quotes around myarray[@]"
    for x in "${myarray[@]}"; do
            echo "ARG[@]: '$x'"
    done
    
    echo "without quotes around myarray[*]"
    for x in ${myarray[*]}; do
            echo "ARG[*]: '$x'"
    done
    
    echo "without quotes around myarray[@]"
    for x in ${myarray[@]}; do
            echo "ARG[@]: '$x'"
    done
    

    And here's it's output:

    with quotes around myarray[*]
    ARG[*]: 'one two three four'
    with quotes around myarray[@]
    ARG[@]: 'one'
    ARG[@]: 'two'
    ARG[@]: 'three four'
    without quotes around myarray[*]
    ARG[*]: 'one'
    ARG[*]: 'two'
    ARG[*]: 'three'
    ARG[*]: 'four'
    without quotes around myarray[@]
    ARG[@]: 'one'
    ARG[@]: 'two'
    ARG[@]: 'three'
    ARG[@]: 'four'
    

    I personally usually want "${myarray[@]}". Now, to answer the second part of your question, ${array[@]} versus $array[@].

    Quoting the bash docs, which you quoted:

    The braces are required to avoid conflicts with the shell's filename expansion operators.

    $ myarray=
    $ myarray[0]="one"
    $ myarray[1]="two"
    $ echo ${myarray[@]}
    one two
    

    But, when you do $myarray[@], the dollar sign is tightly bound to myarray so it is evaluated before the [@]. For example:

    $ ls $myarray[@]
    ls: cannot access one[@]: No such file or directory
    

    But, as noted in the documentation, the brackets are for filename expansion, so let's try this:

    $ touch one@
    $ ls $myarray[@]
    one@
    

    Now we can see that the filename expansion happened after the $myarray exapansion.

    And one more note, $myarray without a subscript expands to the first value of the array:

    $ myarray[0]="one four"
    $ echo $myarray[5]
    one four[5]
    

提交回复
热议问题