IFS ftw (internal field seperator for the win)
| June 24th, 2008If you are trying to run a classic bash for i in $( …. ) loop and things are getting messy, maybe you need to adjust the IFS variable. When I was trying to renames some files with space characters in them I had a really nutty time of it. Then I remembered what I needed to do to win.
Here is basically the problem.
Lets say you have a directory listing like this where each line has only one file name on it:
ls -w1
and the output looks like this in my special test directory:
hello world
install fest
nutter butterwell if you run a bash style for loop on the output of that ls you might cry because of what will happen.
here is the commands I used to test:
let N=0;
for i in $(ls);do echo $N $i; let N++; done;
and here is the result of that:
0 hello
1 world
2 install
3 fest
4 nutter
5 butteiteration of the for loop is caused by the spaces in the file names and the line breaks between file names (as demonstrated by the value of N)
Well, my head has spun on several occasions trying to figure out how to fix that. Usually I try throwing some quotes on things etc.
The real solution is this:
OLDIFS=$IFS;
IFS=$'\n';
let N=0;
for i in $(ls);do echo $N $i; let N++; done;
IFS=$OLDIFS;
and you should get this out:
0 hello world
1 install fest
2 nutter butterI preserver and restore the original IFS with the first and last line of input. the IFS will get it’s value reset when you open a new shell or create a sub shell..unless you use export or change your bashrc… though I think changing it only temporarily is the best policy for me.