Linux/Unix: Understanding IFS (Input Field Separators)

📄 Wiki page | 🕑 Last updated: Dec 22, 2022

IFS is a special shell variable that specifies the characters that will be used as field separators.

Its default value is usually a combination of three whitespace characters: space, tab, and newline.

Printing these characters to the shell output can be a bit tricky, but here are a few examples:

printf %s "$IFS" | od -c


printf %q "$IFS"
printf %s "$IFS" | cat -A
cat -etv <<<"$IFS"

(the first way is the most portable one, others won't necessarily work in all environments)

We can also get the value from the output from the set command:

set | grep -w IFS=

Typically, you'll see something like this:

IFS=$' \t\n'

How does IFS work?

Let's define a simple shell variable, named v:

v="a b:c"

If we try to echo it:

echo "$v"
echo $v

The result in both cases looks the same as our original value:

a b:c
a b:c

But let's see what happens if we change the IFS variable to the colon character:

OLDIFS=IFS
IFS=:

Note: whenever you're changing IFS for the entire process, it's a good idea to save the old value, so you can reverse it easily.

Let's try to run the same command again:

echo "$v"
echo $v

The output of the first command is still the same, but the second one looks different:

a b:c
a b c

In the first case, echo gets a single argument - full value of the variable v, but in the second one, the shell parses that value into the list of arguments, using the IFS variable as a separator.

Note: Splitting of unquoted variables is the default behavior in bash, in zsh you can enable it with setopt shwordsplit.

To understand this better, let's see what individual arguments look like:

set -- $v
echo $1
echo $2

We're using the set command to set the positional arguments ($1, $2, $3, etc.) from our v variable.

As we can see, the standard whitespace separator is now part of the first argument, and the colon character has been used as a separator between arguments:

a b
c

If we go back to the original IFS value:

IFS=OLDIFS
set -- $v
echo $1
echo $2

The standard whitespace is used as a separator:

a
b:c

As we've seen before, the default IFS is a sequence of whitespace characters, so let's try to append it with a colon character:

IFS="$OLDIFS:"
set -- $v
echo $1
echo $2
echo $3

Result:

a
b
c

Once you understand how IFS works, it can be quite handy, especially in combination with positional arguments. For example, since the for loop by default uses positional arguments, we can now iterate over the previously set arguments (with the set command) simply by doing this:

for i; do echo $i; done

Result:

a
b
c

Variable inheritance

In the past, the IFS variable was normally inheritable by the subprocesses, but this has been restricted on pretty much every modern UNIX due to security reasons (for example, programs could be tricked to execute different binaries by setting IFS to "/").

For example, executing something like IFS=: bash -c 'printf %q "$IFS"' will result in the default IFS value:

$' \t\n'

Ask me anything / Suggestions

If you have any suggestions or questions (related to this or any other topic), feel free to contact me. ℹī¸


If you find this site useful in any way, please consider supporting it.