Here is my first script in file named foo.sh
.
IFS=:
for i in foo:bar:baz
do
echo $i
done
This produces the following output.
$ bash foo.sh
foo bar baz
This is my second script.
IFS=:
for i in foo:bar:baz
do
unset IFS
echo $i
done
This produces the following output.
$ bash foo.sh
foo:bar:baz
This is my third script.
IFS=:
var=foo:bar:baz
for i in $var
do
echo $i
done
This produces the following output.
$ bash foo.sh
foo
bar
baz
Why is the output different in all three cases? Can you explain the rules behind the interpretation of IFS and the commands that leads to this different outputs?
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.
IFS=:
for i in foo:bar:baz
do
echo $i
done
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
.
IFS=:
for i in foo:bar:baz
do
unset IFS
echo $i
done
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
.
IFS=:
var=foo:bar:baz
for i in $var
do
echo $i
done
This produces the following output:
foo bar baz
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 "..."
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With