IFS =:在循环结肠分隔值时导致不同的行为

时间:2017-09-20 05:11:41

标签: bash shell for-loop ifs

实验1

这是我在文件中的第一个名为foo.sh的脚本。

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

这会产生以下输出。

$ bash foo.sh
foo bar baz

实验2

这是我的第二个剧本。

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解释背后的规则以及导致的命令 这个不同的产出?

1 个答案:

答案 0 :(得分:15)

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

要了解发生了什么, 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.

关键是“...的结果”部分,它非常微妙。 也就是说,单词拆分发生在某些操作的结果上, 如上所列:参数扩展的结果, 命令替换的结果,等等。 不对字符串文字执行单词拆分,例如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

实验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

实验3

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

这会产生以下输出:

foo
bar
baz

$var 的参数扩展后, 使用IFS的值执行单词拆分, 因此for有3个要迭代的值,foobarbazecho的行为在这里是微不足道的, 输出是每行一个字。

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

这并不奇怪。 字符串文字很像用双引号括起来的表达式,你不希望在"..."上分词。