将定界字符串解析为 Bash 中的数组 - 为什么“$var”与 $var 不同,尽管 $var 没有空格?

Parsing a delimited string into an array in Bash - why is "$var" different from $var though $var has no spaces?

我是运行Bash版本4.2.25。这是我的代码:

#!/usr/bin/env bash

string="one:two:three:four"

# without quotes
IFS=: read -ra array_1 <<< $string
for i in "${array_1[@]}"; do printf "i = [$i]\n"; done
# output:
# i = [one two three four]

# with quotes
IFS=: read -ra array_2 <<< "$string"
for i in "${array_2[@]}"; do printf "i = [$i]\n"; done
# output:
# i = [one]
# i = [two]
# i = [three]
# i = [four]

如何解释行为差异?

它看起来像一个错误。我回顾了 CHANGES and couldn't find anything specific, but on cygwin bash 4.3.48(8), both quoted and unquoted give the expected output (four lines). Sometime when I have bandwidth to burn I'll clone the repo and blame redir.c 以查看是否可以找到一些相关的提交。

我无法在 Linux 使用 bash 4.2.46 和 bash 4.3.30 重现您的问题。然而,这里有一个改编版本,确实显示了所描述的行为:

string="one:two:three:four"
IFS=:

read -ra array_1 <<< $string
for i in "${array_1[@]}"; do printf "i = [$i]\n"; done
# i = [one two three four]

read -ra array_2 <<< "$string"
for i in "${array_2[@]}"; do printf "i = [$i]\n"; done
# i = [one]
# i = [two]
# i = [three]
# i = [four]

发生这种情况是因为变量实际上并未在 space 上拆分,它们在 $IFS 上拆分(默认为 space、制表符和换行符)。

因为我们已经覆盖了 $IFS,它是带有冒号的值,我们必须小心引用。空格不再重要。

源码显示Bashhardcodes a space in string_list, called through write_here_string。当 IFS 不包含 space 时,扩展为多个单词的字符串将不再 read 变成类似行的标记,从而使差异更加明显。

PS:这是一个很好的例子,说明为什么我们应该始终引用我们的变量,即使我们知道它们包含什么。