我觉得这是一个非常有趣的实验。
谢谢你。
要理解正在发生的事情,
来自man bash
的相关部分如下:
字符串拆分
在未出现在双引号内的参数扩展、命令替换和算术扩展结果上对其进行字符串拆分。
关键在于"results of ..."部分,它非常微妙。
也就是说,字符串拆分发生在特定操作的结果上,
如参数扩展的结果、命令替换的结果等。
字符串拆分不会对字符串文字(例如foo:bar:baz
)执行。
让我们看看这个逻辑在您的示例中如何运作。
实验1
IFS=:
for i in foo:bar:baz
do
echo $i
done
这将产生以下输出:
foo bar baz
对于字面值foo:bar:baz
,没有执行单词拆分,
因此,只要涉及for
循环,IFS
的值是什么都无所谓。
在参数扩展后,会对$i
的值执行单词拆分,
因此,foo:bar:baz
被拆分为3个单词,并传递给echo
,因此输出是foo bar baz
。
实验2
IFS=:
for i in foo:bar:baz
do
unset IFS
echo $i
done
这将产生以下输出:
foo:bar:baz
再次说明,
对于字面值foo:bar:baz
,不会执行任何单词拆分,
因此无论IFS
的值是什么,
就for
循环而言都没有关系。
在参数扩展后,将执行单词拆分 $i
的值,
但由于IFS
未设置,
它使用默认值来执行拆分,
即<space><tab><newline>
。
但由于foo:bar:baz
不包含任何这些字符,
因此保持不变,输出结果为foo:bar:baz
。
实验三
IFS=:
var=foo:bar:baz
for i in $var
do
echo $i
done
这将产生以下输出:
foo
bar
baz
在 $var
参数扩展之后,使用 IFS
的值执行单词分割,因此 for
有三个值要迭代,即 foo
、bar
和 baz
。
这里的 echo
行为很简单,输出每行一个单词。
底线是:字面值不会执行单词分割。
单词拆分仅在特定操作的结果上执行。
这并不奇怪。
字符串字面值很像用双引号括起来的表达式,您不会期望在 "..."
上进行单词拆分。
for i in foo:bar:baz
的行为和echo $i
中未引用扩展的行为。如果你使用echo "$i"
进行测试,那么这将让你仅隔离出for i in foo:bar:baz
的行为(以及它如何完全不受IFS
影响),这可以说是你问题的核心 - 相比之下,一个仅询问echo $i
行为而没有周围的for
的问题将是一个简单的重复,可以通过指向已经存在的问题和答案来回答。 - Charles Duffy