IFS – Internal Field Separator

September 26, 2007

It seems like an esoteric concept, but it’s actually very useful.

If your input file is “1 apple steve@example.com”, then your script could say:

while read qty product customer
do
  echo "${customer} wants ${qty} ${product}(s)"
done

The read command will read in the three variables, because they're spaced out from each other.

However, critical data is often presented in spreadsheet format. If you save these as CSV files, it will come out like this:

1,apple,steve@example.com

This contains no spaces, and the above code will not be able to understand it. It will take the whole thing as one item - the first thing, quanity, $qty, and set the other two fields as blank.

The way around this, is to tell the entire shell, that "," (the comma itself) separates fields; it's the "internal field separator", or IFS.

The IFS variable is set to space/tab/newline, which isn't easy to set in the shell, so it's best to save the original IFS to another variable, so you can put it back again after you've messed around with it. I tend to use "oIFS=$IFS" to save the current value into "oIFS".

Also, when the IFS variable is set to something other than the default, it can really mess with other code.

Here's a script I wrote today to parse a CSV file:

#!/bin/sh
oIFS=$IFS     # Always keep the original IFS!
IFS=","          # Now set it to what we want the "read" loop to use
while read qty product customer
do
  IFS=$oIFS
  # process the information
  IFS=","       # Put it back to the comma, for the loop to go around again
done < myfile.txt

It really is that easy, and it's very versatile. You do have to be careful to keep a copy of the original (I always use the name oIFS, but whatever suits you), and to put it back as soon as possible, because so many things invisibly use the IFS - grep, cut, you name it. It's surprising how many things within the "while read" loop actually did depend on the IFS being the default value.


Follow

Get every new post delivered to your Inbox.