代码之家  ›  专栏  ›  技术社区  ›  Telemachus MrJames

在bash完成的上下文中,对$array[*]与$array[@]的混淆

  •  61
  • Telemachus MrJames  · 技术社区  · 15 年前

    我第一次尝试编写一个bash完成,我对两种取消对bash数组的引用方式有点困惑。( ${array[@]} ${array[*]} )

    下面是相关的代码块(顺便说一下,它可以工作,但我想更好地理解它):

    _switch()
    {
        local cur perls
        local ROOT=${PERLBREW_ROOT:-$HOME/perl5/perlbrew}
        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        perls=($ROOT/perls/perl-*)
        # remove all but the final part of the name
        perls=(${perls[*]##*/})
    
        COMPREPLY=( $( compgen -W "${perls[*]} /usr/bin/perl" -- ${cur} ) )
    }
    

    巴什 documentation says :

    数组的任何元素都可以使用$name[下标]引用。需要大括号以避免与shell的文件名扩展运算符冲突。如果下标是__@226;_或__*_,则该词将扩展到数组名的所有成员。只有当单词出现在双引号中时,这些下标才会有所不同。如果单词是双引号的,$name[*]展开为一个单词,每个数组成员的值由ifs变量的第一个字符分隔,并且$name[@]展开名称的每个元素为一个单独的单词。

    现在我想我明白了 compgen -W 需要一个包含可能替代词的单词列表的字符串,但在此上下文中,我不理解“$name[@]将名称的每个元素扩展为一个单独的单词”的含义。

    长话短说: ${SARD[*] } 作品; ${Salt[@ ] } 没有,我想知道原因,我想更好地理解 ${Salt[@ ] } 扩展成

    2 回复  |  直到 8 年前
        1
  •  77
  •   Gordon Davisson    8 年前

    (这是我对卡莱布·佩德森答案的评论的扩展——请参阅该答案,了解对 [@] VS [*] )

    当bash(或任何类似的shell)解析命令行时,它将其拆分为一系列“单词”(我将称之为“shell单词”,以避免以后混淆)。通常,shell单词由空格(或其他空白)分隔,但可以通过转义或引用将空格包含在shell单词中。两者之间的区别 [@ ] [*] -双引号中的扩展数组是 "${myarray[@]}" 导致数组的每个元素被视为单独的shell字,而 "${myarray[*]}" 结果是一个shell单词,数组中的所有元素都由空格分隔(或 IFS 是)。

    通常, [@ ] 行为就是你想要的。假设我们有 perls=(perl-one perl-two) 使用 ls "${perls[*]}" --相当于 ls "perl-one perl-two" ,它将查找名为 perl-one perl-two 可能不是你想要的。 ls "${perls[@]}" 等于 ls "perl-one" "perl-two" 更可能做一些有用的事情。

    提供完成词列表(我将称之为comp-words以避免与shell-words混淆),以便 compgen 不同的;不同的 -W 选项接受comp单词列表,但它必须以单个shell单词的形式出现,comp单词之间用空格分隔。注意,接受参数的命令选项总是(至少据我所知)接受一个shell单词——否则就无法知道选项的参数何时结束,常规命令参数(/other option flags)何时开始。

    更详细地说:

    perls=(perl-one perl-two)
    compgen -W "${perls[*]} /usr/bin/perl" -- ${cur}
    

    相当于:

    compgen -W "perl-one perl-two /usr/bin/perl" -- ${cur}
    

    …这是你想要的。另一方面,

    perls=(perl-one perl-two)
    compgen -W "${perls[@]} /usr/bin/perl" -- ${cur}
    

    相当于:

    compgen -W "perl-one" "perl-two /usr/bin/perl" -- ${cur}
    

    …这完全是胡说八道:“perl one”是附加到-w标志的惟一comp字,而compgen将作为要完成的字符串的第一个实参是“perl two/usr/bin/perl”。我希望康普根会抱怨有人给了它额外的论据(“—”和任何在$cur中的论据),但显然它忽略了这些论据。

        2
  •  45
  •   jfMR    8 年前

    您的标题询问 ${array[@]} 对战 ${array[*]} 但是你问起 $array[*] 对战 $array[@] 这有点令人困惑。我会回答两个问题:

    当引用数组变量并使用 @ 作为下标,数组中的每个元素都被扩展为其全部内容,而不考虑空格(实际上是 $IFS )可能存在于该内容中。当你用星号的时候( * )作为下标(不管是否加引号),它可以扩展到新的内容,这是通过在处拆分每个数组元素的内容而创建的。 IFS .

    下面是脚本示例:

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

    它的输出是:

    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'
    

    我个人通常想要 "${myarray[@]}" . 现在,回答你问题的第二部分, ${Salt[@ ] } 对战 $数组[ @ ] .

    引用您引用的bash文档:

    需要大括号以避免与shell的文件名扩展运算符冲突。

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

    但是,当你这样做的时候 $myarray[@] 美元符号与 myarray 所以它是在 [@] . 例如:

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

    但是,如文档中所述,括号用于扩展文件名,因此让我们尝试一下:

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

    现在我们可以看到文件名扩展发生在 $myarray 外露。

    还有一个音符, 美元数组 如果没有下标,则扩展到数组的第一个值:

    $ myarray[0]="one four"
    $ echo $myarray[5]
    one four[5]
    
    推荐文章