A confusion about ${array[*]} versus ${array[@]} in the context of a Bash completion
我正在尝试第一次编写Bash完成,我对解除引用Bash数组(
这是相关的代码块(顺便说一句,它可以工作,但我想更好地理解它):
1 2 3 4 5 6 7 8 9 10 11 12 | _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} ) ) } |
Bash的文档说:
Any element of an array may be referenced using ${name[subscript]}. The braces are required to avoid conflicts with the shell's filename expansion operators. If the subscript is ‘@’ or ‘*’, the word expands to all members of the array name. These subscripts differ only when the word appears within double quotes. If the word is double-quoted, ${name[*]} expands to a single word with the value of each array member separated by the first character of the IFS variable, and ${name[@]} expands each element of name to a separate word.
现在我想我明白
长话短说:
(这是我对Kaleb Pederson的回答的评论的扩展 - 看到对
当bash(或任何类似的shell)解析命令行时,它会将其拆分为一系列"单词"(我将其称为"shell-words"以避免以后出现混淆)。通常,shell-words由空格(或其他空格)分隔,但空格可以通过转义或引用来包含在shell-word中。双引号中
通常,
提供完成单词列表(我将其称为comp-words以避免与shell-words混淆)到
更详细:
1 2 | perls=(perl-one perl-two) compgen -W"${perls[*]} /usr/bin/perl" -- ${cur} |
相当于:
1 | compgen -W"perl-one perl-two /usr/bin/perl" -- ${cur} |
......做你想做的事。另一方面,
1 2 | perls=(perl-one perl-two) compgen -W"${perls[@]} /usr/bin/perl" -- ${cur} |
相当于:
1 | compgen -W"perl-one""perl-two /usr/bin/perl" -- ${cur} |
...这完全是废话:"perl-one"是唯一附加到-W标志的comp-word,第一个真正的参数 - compgen将作为要完成的字符串 - 是"perl-two"在/ usr / bin中/ perl的"。我希望compgen抱怨它已被给予额外的参数(" -"以及$ cur中的任何内容),但显然它只是忽略了它们。
你的标题询问
引用数组变量并使用
这是示例脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #!/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 |
这是它的输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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' |
我个人通常想要
引用你引用的bash文档:
The braces are required to avoid conflicts with the shell's filename expansion operators.
1 2 3 4 5 | $ myarray= $ myarray[0]="one" $ myarray[1]="two" $ echo ${myarray[@]} one two |
但是,当你执行
1 2 | $ ls $myarray[@] ls: cannot access one[@]: No such file or directory |
但是,如文档中所述,括号用于文件名扩展,所以让我们试试这个:
1 2 3 | $ touch one@ $ ls $myarray[@] one@ |
现在我们可以看到文件名扩展发生在
还有一点,没有下标的
1 2 3 | $ myarray[0]="one four" $ echo $myarray[5] one four[5] |