尝试将一个字符串分割为两个变量

14

我想将一个字符串分成两个变量(而不必使用while循环):

var="hello:world"
IFS=':' read var1 var2 <<< $var

echo "var1: $var1"
echo "var2: $var2"

但我没有得到期望的结果:

var1: 'hello world'
var2: ''

请问是否有可能用这种方式(或类似的方式)来完成?


请注意,这并不完全是重复的;上面的代码是正确的,但受到4.x中的一个错误的影响(在4.3中已修复),该错误在链接的重复内容中没有得到解决。 - chepner
基于此,适当的行为是重新打开这个问题(我刚刚做了),并接受chepner的答案。 - fedorqui
2个回答

25

这是Bash 4.2中的一个bug。请查看chepner的答案以获取正确的解释。


这与引号有关。使用:

IFS=':' read var1 var2 <<< "$var"
                           ^    ^

代替

IFS=':' read var1 var2 <<< $var

查看结果:

$ IFS=':' read var1 var2 <<< "$var"
$ echo "var1=$var1, var2=$var2"
var1=hello, var2=world

但是

$ IFS=':' read var1 var2 <<< $var
$ echo "var1=$var1, var2=$var2"
var1=hello world, var2=

很高兴看到,@coda,引用总是很重要的。记住,如果你的问题已经解决,你可以接受答案! - fedorqui
2
@chepner我发现另一个有趣的行为:如果你这样做IFS=':' read var1 var2 <<< hello:bye,那么它会被正确分割,而如果它来自一个变量,它就不会。 - fedorqui
奇怪。我已经提交了一个错误报告,引用了这个问题。 我注意到使用一个文档(应该等同于 ... <<< "$var")也可以工作。 - chepner
@chepner 很有趣。你指的是使用 here document 的 <<< EOF ... EOF 吗?另外,你能否让我知道他们对这个 bug 说了什么?或者给我一个相关链接就好了。 - fedorqui
2
当然。没错,<<EOF$varEOF(在预期位置换行)与引用的 here 字符串相同。漏洞是通过电子邮件报告的,因此没有漏洞跟踪器链接(但)。 - chepner
显示剩余2条评论

14

供未来读者参考:

经过与开发人员讨论后,这似乎是 bash 4.2 中的一个 bug,并已在即将发布的 4.3 版本中修复。从devel 分支的更改日志中可以看到:

rrrr. 当 IFS 出现在临时环境中并用于重定向时,修复了多个问题。

虽然始终建议使用引号扩起参数扩展,但 OP 的代码应该无需引号就能按预期工作。


以下是该 bug 的解释。

var="hello:world"
IFS=':' read var1 var2 <<< $var

$var应该不带引号且只包含单个单词,因为它不包含全局变量IFS中的任何字符(也就是说,没有空格)。然后read将看到字符串hello:world。由于它接收了两个参数,所以它会使用本地IFS的值进行词分割,生成helloworld,并将它们分别赋给var1var2

bug在于这里的字符串似乎使用传递给read的“泄漏”IFS值部分分割。结果,字符串变成了hello world,但仍然被read视为单个单词。由于该单词不包含:,因此read不会将其拆分成两个单词,并将整个字符串赋给var1

bash 4.3中,如文档所述,$var的扩展不会经过词分割,作为<<<运算符的参数;代码:

var="hello:1:2 world"
IFS=: read var1 var2 <<< $var

var1设置为hello,将var2设置为1:2 world


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