Bash: spaces turn into newlines on for loops

Have you ever tried to loop through a set of items in a for loop in bash just to discover that bash turns spaces into newlines making your script to break?

Well, if you are in a hurry, use this before starting the for loop and come back afterwards for an explanation of what happened there:

1
export IFS=$'\n';

Your final result might look like this:

1
2
3
4
export IFS=$'\n';
for stuff in `ls -1 | grep -iE '[a-z]+'`;
do du "$stuff" -hs;
done

Welcome back. Now, here’s what happened, IFS is a variable set by bash which contains a set of separators in order to perform word splitting. That is, every time bash is going to determine  which sequence of characters will be considered as a single unit, it will assume as such each sequence of characters that it contained between separators.

By default, the shell will set IFS to contain 3 values as separators: spaces, tab, newlines. So, if one of the elements in your loop contains a character considered as a separator (in our case, the space) the shell will consider each set of character between spaces as one additional element.

In a more graphical example, the following element:

1
My Car Picture.png

…would be considered as three different elements:

1
2
3
My
Car
Picture.png

And from this point on your script will start to yield errors and unexpected results.

So, what we did to correct this was to override the value of IFS in order to having it only consider newline ($’\n’) as an element separator.

You can consult the bash man page for further information.

Feel free to leave a comment if you found this article helpful or think there’s something to improve about it.

Leave a Reply

Your email address will not be published. Required fields are marked *