Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在bash完成上下文中${array[*]}与${array[@]}之间的混淆_Arrays_Bash_Bash Completion - Fatal编程技术网

Arrays 在bash完成上下文中${array[*]}与${array[@]}之间的混淆

Arrays 在bash完成上下文中${array[*]}与${array[@]}之间的混淆,arrays,bash,bash-completion,Arrays,Bash,Bash Completion,我第一次尝试编写一个bash补全,我对取消对bash数组的引用的两种方法(${array[@]}和${array[*]})有点困惑 下面是相关的代码块(顺便说一句,它可以工作,但我想更好地理解它): bash的: 数组的任何元素都可以使用${name[subscript]}引用。大括号是必需的,以避免与shell的文件名扩展运算符冲突。如果下标为“@”或“*”,则该词将扩展到数组名称的所有成员。只有当单词出现在双引号内时,这些下标才会不同。如果单词是双引号,${name[*]}将展开为单个单词,

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

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

bash的:

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

现在我想我明白了,
compgen-W
需要一个字符串,其中包含一个可能的备选词列表,但在本文中,我不明白“${name[@]}将name的每个元素扩展为一个单独的词”是什么意思


长话短说:
${array[*]}
有效<代码>${array[@]}没有。我想知道为什么,我想更好地理解
${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[@]}”
。现在,回答问题的第二部分,
${array[@]}
$array[@]
的对比

引用您引用的bash文档:

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

但是,当您执行
$myarray[@]
时,美元符号与
myarray
紧密绑定,因此在
[@]
之前对其求值。例如:

$ ls $myarray[@]
ls: cannot access one[@]: No such file or directory
但是,如文档中所述,括号用于文件名扩展,因此让我们尝试以下方法:

$ touch one@
$ ls $myarray[@]
one@
现在我们可以看到文件名扩展发生在
$myarray
扩展之后

还有一个注意事项,
$myarray
不带下标扩展到数组的第一个值:

$ myarray[0]="one four"
$ echo $myarray[5]
one four[5]
(这是我对卡莱布·佩德森答案的评论的扩展——关于
[@]
[*]
的更一般处理,请参见该答案)

当bash(或任何类似的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”
,它更有可能做一些有用的事情

compgen
提供一个补全词列表(我称之为comp词以避免与shell词混淆)是不同的;
-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}
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}
compgen -W "perl-one" "perl-two /usr/bin/perl" -- ${cur}

…这完全是胡说八道:“perl one”是附加到-W标志的唯一comp字,第一个真正的参数——compgen将把它作为要完成的字符串——是“perl two/usr/bin/perl”。我希望compgen会抱怨它被赋予了额外的参数(“--”以及$cur中的任何内容),但显然它只是忽略了它们。

还了解了
IFS
如何根据
@
*
以及引号与未引号对输出产生不同的影响。我很抱歉,因为这在本文中非常重要,但我一直是指
${array[*]}
${array[@]}
。缺少大括号只是粗心大意。除此之外,你能解释一下
${array[*]}
compgen
命令中会扩展成什么吗?也就是说,在这种情况下,将数组分别扩展到每个元素意味着什么?换言之,你(像几乎所有的源代码一样)会说
${array[@]}
通常是一种方法。我想了解的是为什么在这种情况下只有
${array[*]}
有效。我