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

Lon*_*ner 12 bash shell for-loop ifs

实验1

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

IFS=:
for i in foo:bar:baz
do
    echo $i
done
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出.

$ bash foo.sh
foo bar baz
Run Code Online (Sandbox Code Playgroud)

实验2

这是我的第二个脚本.

IFS=:
for i in foo:bar:baz
do
    unset IFS
    echo $i
done
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出.

$ bash foo.sh
foo:bar:baz
Run Code Online (Sandbox Code Playgroud)

实验3

这是我的第三个脚本.

IFS=:
var=foo:bar:baz
for i in $var
do
    echo $i
done
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出.

$ bash foo.sh
foo
bar
baz
Run Code Online (Sandbox Code Playgroud)

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

Sto*_*ica 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
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出:

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
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出:

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
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出:

foo
bar
baz

的参数膨胀后$var,词的拆分是使用的值来进行IFS,因此for具有3个值来遍历,foo,bar,和baz.这里的行为echo是微不足道的,输出是每行一个字.


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

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

  • 很好的答案,这应该得到赏金!这里也有类似的问题/答案:[在Bash中使用printf进行分词并将IFS设置为非空白字符](/sf/answers/3021434951/). (2认同)