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

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


I found this a very interesting experiment.Thank you for that.


To understand what is going on,the relevant section from man bash is this:

  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.

The key is the "results of ..." part, and it's very subtle.That is, word splitting happens on the result of certain operations,as listed there: the result of parameter expansion,the result of command substitution, and so on.Word splitting is not performed on string literals such as foo:bar:baz.

Let's see how this logic plays out in the context of your examples.

Experiment 1

IFS=:for i in foo:bar:bazdo    echo $idone

This produces the following output:

foo bar baz

No word splitting is performed on the literal foo:bar:baz,so it doesn't matter what is the value of IFS,as far as the for loop is concerned.

Word splitting is performed after parameter expansion on the value of $i,so foo:bar:baz is split to 3 words,and passed to echo, so the output is foo bar baz.

Experiment 2

IFS=:for i in foo:bar:bazdo    unset IFS    echo $idone

This produces the following output:

foo:bar:baz

Once again,no word splitting is performed on the literal foo:bar:baz,so it doesn't matter what is the value of IFS,as far as the for loop is concerned.

Word splitting is performed after parameter expansion on the value of $i,but since IFS was unset,its default value is used to perform the split,which is <space><tab><newline>.But since foo:bar:baz doesn't contain any of those,it remains intact, so the output is foo:bar:baz.

Experiment 3

IFS=:var=foo:bar:bazfor i in $vardo    echo $idone

This produces the following output:

foobarbaz

After the parameter expansion of $var,word splitting is performed using the value of IFS,and so for has 3 values to iterate over, foo, bar, and baz.The behavior of echo is trivial here,the output is one word per line.


The bottomline is: word splitting is not performed on literal values.Word splitting is only performed on the result of certain operations.

This is not all that surprising.A string literal is much like an expression written enclosed in double-quotes, and you wouldn't expect word splitting on "...".