在Bash中将分隔字符串转换为数组 - 为什么"$var"和$var不同,尽管$var没有空格?

4

我正在使用 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]

什么解释了行为的差异?
2个回答

3

我无法在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]

这是因为变量实际上不是按空格分隔的,而是按$IFS(默认为空格、制表符和换行符)进行分隔。

由于我们已覆盖了$IFS的值,将其设置为冒号,因此在引用变量时必须小心引号。空格不再重要。

源代码显示Bash 硬编码一个空格string_list中,通过write_here_string调用。当IFS不包括空格时,扩展为多个单词的字符串将不再按相似的方式读取成标记,使差异更加明显。

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


1

看起来像是一个漏洞。我回头查看了 CHANGES,没有找到任何具体的东西,但在cygwin bash 4.3.48(8)上,引号和未引用的都能给出预期的输出(四行)。有时候当我有充足的时间时,我会克隆repo并责备redir.c以查看是否可以找到一些相关的提交。


这确实是一个漏洞,在4.3中部分解决,并在4.4中完成(?)。 - chepner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接