IFS=: 在循环以冒号分隔的值时导致不同的行为

IFS=: leads to different behavior while looping over colon-separated values

实验 1

这是我在名为 foo.sh.

的文件中的第一个脚本
IFS=:
for i in foo:bar:baz
do
    echo $i
done

这会产生以下输出。

$ bash foo.sh
foo bar baz

实验二

这是我的第二个脚本。

IFS=:
for i in foo:bar:baz
do
    unset IFS
    echo $i
done

这会产生以下输出。

$ bash foo.sh
foo:bar:baz

实验 3

这是我的第三个脚本。

IFS=:
var=foo:bar:baz
for i in $var
do
    echo $i
done

这会产生以下输出。

$ bash foo.sh
foo
bar
baz

为什么三种情况的输出都不一样?你能解释一下吗 IFS 解释背后的规则和导致的命令 这种不同的输出?

我发现这是一个非常有趣的实验。 谢谢你。


要了解正在发生的事情, man bash 的相关部分是这样的:

  Word Splitting
      The  shell  scans the results of parameter expansion, command substitu-
      tion, and arithmetic expansion that did not occur within double  quotes
      for word splitting.

关键是"results of ..."部分,非常隐蔽。 也就是说,分词发生在某些操作的结果上, 如那里所列:参数扩展的结果, 命令替换的结果,等等。 不对 foo:bar:baz.

等字符串文字执行分词

让我们看看这个逻辑在您的示例上下文中如何发挥作用。

实验 1

IFS=:
for i in foo:bar:baz
do
    echo $i
done

这会产生以下输出:

foo bar baz

不对文字进行分词foo:bar:baz, 所以 IFS 的值是多少并不重要, 就 for 循环而言。

$i的值进行参数扩展后进行分词, 所以 foo:bar:baz 被分成 3 个词, 并传递给 echo,因此输出为 foo bar baz.

实验二

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.

实验 3

IFS=:
var=foo:bar:baz
for i in $var
do
    echo $i
done

这会产生以下输出:

foo
bar
baz

$var的参数展开后, 使用IFS的值进行分词, 因此 for 有 3 个值要迭代,foobarbazecho 的行为在这里很简单, 输出是每行一个字。


底线是:不对文字值执行分词。 分词只对某些操作的结果进行。

这并不奇怪。 字符串文字很像用双引号括起来的表达式,您不会期望在 "...".

上进行分词