I'm going through a Bash tutorial, and specifically the subject of word splitting.
This script, called "args", helps demonstrate word splitting examples:
#!/usr/bin/env bash
printf "%d args:" $#
printf " <%s>" "$@"
echo
An example:
$ ./args hello world, here is "a string of text!"
5 args: <hello> <world,> <here> <is> <a string of text!>
So far so good. I understand how this works.
However, when I replace IFS with a non-whitespace character, say :
, the script does not perform word splitting if I pass the string directly as an argument.
$ ./args one:two:three
1 args: <one:two:three>
However, the script does perform word splitting on the same string if I (1) assign the string to a variable, and then (2) pass the string to the script via parameter expansion.
$ IFS=:
$ variable="one:two:three"
$ ./args $variable
3 args: <one> <two> <three>
Why? Specifically, why does passing the string as an argument undergo word splitting when IFS is unset and the delimiters are whitespace characters, but not when IFS is set to non-whitespace characters?
When I use read
instead of this script, the same string also undergoes word splitting as expected.
$ IFS=:
$ read a b c
one:two:three
$ echo $a $b $c
one two three
You can read more about word splitting here.
When you pass the bare string
one:two:three
as an argument with IFS set to:
, Bash doesn't do word splitting because the bare string is not one of parameter expansion, command substitution, or arithmetic expansion contexts.However, when the same string is assigned to a variable and the variable is passed to the script unquoted, word splitting does occur as it is a case of parameter expansion.
The same thing applies to these as well (command substitution):
As documented,
read
command does do word splitting on every line read, unless IFS has been set to an empty string.