Bash mapfile 数组计数不同

Bash mapfile 数组计数不同

我做了以下事情:

mapfile -t array < <(commands)

其中commands将产生换行符分隔的输出。

然后根据结果,如果数组中没有任何内容,则退出,否则继续:

[[ "${#array[@]}" -eq 0 ]] && exit

...

问题是这个条件永远不会被满足。因为当 saidcommands不返回任何内容时,${#array[@]}返回 1 而不是 0。

但如果我按如下方式分配数组,则计数正确:

array=($(commands))

我的测试:

$ declare -a array
$ array=($(echo))
$ echo ${#array[@]}
0
$ unset array
$ mapfile -t array < <(echo)
$ echo ${#array[@]}
1

为什么?


最初我使用了该array=($(commands))格式,但shellcheck建议我改为使用mapfile

GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)

答案1

如果命令中不打印任何内容,您将得到以下结果:

$ mapfile -t array < <(printf ''); echo "num: ${#array[@]}"; declare -p array
num: 0
declare -a array=()

如果它打印一个空行,您将得到以下结果:

$ mapfile -t array < <(echo); echo "num: ${#array[@]}"; declare -p array
num: 1
declare -a array=([0]="")

空行产生一个空元素,非常恰当。

如果您的程序产生这样的空行并且您无法阻止它,您可以使用例如删除它们grep。或者检查单个数组元素是否为空。

使用以下命令删除空行grep

$ mapfile -t array < <(echo | grep .); echo "num: ${#array[@]}"; declare -p array
num: 0
declare -a array=()

检查是否有空元素:

$ mapfile -t array < <(echo);
$ if [[ "${#array[@]}" = 0 || "${#array[@]}" = 1 && "${array[0]}" = "" ]]; then 
    echo "empty list or only one empty element"; 
 fi
empty list or only one empty element

array=($(commands))

它是不同的,因为命令替换的结果经过分词,这也会删除所有尾随空格。并用空格分割行。 (命令替换本身也会删除任何尾随换行符,但这在这里并不重要。)

相关内容