如果 Bash 数组不能包含空字符串,这个数组是如何做到的?

如果 Bash 数组不能包含空字符串,这个数组是如何做到的?

我最近发现你无法将空字符串传递给 Bash 数组。这很棘手,因为我试图将空字符串值插入到数组中。

然而,我注意到 Bash 完成变量 COMP_WORDS 可以包含空值。

我编写了一个虚拟完成脚本来说明这一点,并启用了调试选项:

  1 #!/bin/bash
  2 _comp() {
  3     set -xv
  4     for i in ${!COMP_WORDS[@]}; do
  5         echo "<${COMP_WORDS[$i]}>"                                                                                         
  6     done
  7     set +xv
  8     local cur=${COMP_WORDS[$COMP_CWORD]}
  9 
 10     local arr=(apple banana mango pineapple)
 11     COMPREPLY=()
 12     COMPREPLY=($(compgen -W "${arr[*]}" -- $cur))
 13 
 14 }
 15 
 16 complete -F _comp dummy

如果我获取该文件,然后输入以下内容:

dummy apple   banana

然后,如果我将光标移回苹果和香蕉之间的中间空间(下面用下划线表示)...

dummy apple _ banana

然后,如果我点击选项卡,我会从生成的调试中得到以下输出,显示四个数组元素,'dummy''apple''''banana'

for i in '${!COMP_WORDS[@]}'
+ echo '<dummy>'
<dummy>
+ for i in '${!COMP_WORDS[@]}'
+ echo '<apple>'
<apple>
+ for i in '${!COMP_WORDS[@]}'
+ echo '<>'
<>
+ for i in '${!COMP_WORDS[@]}'
+ echo '<banana>'
<banana>

因此 COMP_WORDS 数组显然能够存储某种空字符串。尽管有趣的是,这确实不是如果我使用常规的 for 循环,访问数组元素而不是索引,就会发生这种情况。即,如果我将调试部分中的 for 循环更改为此...

for i in ${COMP_WORDS[@]}; do
    echo "<$i>"
done 

然后我得到以下调试输出,仅显示三个数组元素: 'dummy' 'apple' 'banana'

for i in '${COMP_WORDS[@]}'
+ echo '<dummy>'
<dummy>
+ for i in '${COMP_WORDS[@]}'
+ echo '<apple>'
<apple>
+ for i in '${COMP_WORDS[@]}'
+ echo '<banana>'
<banana>

我尝试用 - 来回显数组的长度${#COMP_WORDS[@]}- 对于此输入,它显示的长度为四。所以它显然包含四个元素,其中一个是空字符串。

对我来说,这似乎是非常奇怪的行为。我的问题有两个:

  1. 当普通数组显然不能存储空字符串时,COMP_WORDS 数组能够存储空字符串的解释是什么?

  2. 为什么当我使用常规 for 循环时看不到空字符串,但当我通过索引访问数组元素时却可以看到它?

答案1

您似乎将空字符串""与 NULL 字符混淆了\0。他们不一样。您可以在数组和变量中使用空字符串:

$ a=(aa "" "b")
$ echo "${#a[@]}"
3
$ printf -- '- %s\n' "${a[@]}"
- aa
- 
- b
$ for i in "${a[@]}"; do
> printf '%s\n' "$i"
> done
aa

b

一些条件表达式在 Bash 中甚至允许测试字符串是否为空:

-z 字符串

True if the length of string is zero.

-n 字符串 字符串

True if the length of string is non-zero.

也可以看看什么时候需要双引号?

相关内容