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:
export IFS=$'\n';
Your final result might look like this:
export IFS=$'\n'; for stuff in `ls -1 | grep -iE '[a-z]+'`; do du "$stuff" -hs; done
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 is 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 characters between spaces as one additional element.
In a more graphical ilustration, the following element:
My Car Picture.png
..would be considered as three different elements:
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.
Use the printf function in order to know the current value of the IFS variable:
$ printf %q "$IFS" $' \t\n'
From printf man page:
%q ARGUMENT is printed in a format that can be reused as shell input, escaping non-printable characters with the proposed POSIX $” syntax.
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.