Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

The following few threads on this site and StackOverflow were helpful for understanding how IFS works:

But I still have some short questions. I decided to ask them in the same post since I think it may help better future readers:

Q1. IFS is typically discussed in the context of "field splitting". Is field splitting the same as word splitting ?

Q2: The POSIX specification says:

If the value of IFS is null, no field splitting shall be performed.

Is setting IFS= the same as setting IFS to null? Is this what is meant by setting it to an empty string too?

Q3: In the POSIX specification, I read the following:

If IFS is not set, the shell shall behave as if the value of IFS is <space>, <tab> and <newline>

Say I want to restore the default value of IFS. How do I do that? (more specifically, how do I refer to <tab> and <newline>?)

Q4: Finally, how would this code:

while IFS= read -r line
do    
    echo $line
done < /path_to_text_file

behave if we we change the first line to

while read -r line # Use the default IFS value

or to:

while IFS=' ' read -r line
share|improve this question

3 Answers 3

up vote 6 down vote accepted
  1. Yes, they are the same.
  2. Yes.
  3. In bash, and similar shells, you could do something like IFS=$' \t\n'. Otherwise, you could insert the literal control codes by using [space] CTRL+V [tab] CTRL+V [enter]. If you are planning to do this, however, it's better to use another variable to temporarily store the old IFS value, and then restore it afterwards (or temporarily override it for one command by using the var=foo command syntax).
    • The first code snippet will put the entire line read, verbatim, into $line, as there are no field separators to perform word splitting for. Bear in mind however that since many shells use cstrings to store strings, the first instance of a NUL may still cause the appearance of it being prematurely terminated.
    • The second code snippet may not put an exact copy of the input into $line. For example, if there are multiple consecutive field separators, they will be made into a single instance of the first element. This is often recognised as loss of surrounding whitespace.
    • The third code snippet will do the same as the second, except it will only split on a space (not the usual space, tab, or newline).
share|improve this answer
2  
The answer to Q2 is wrong: an empty IFS and an unset IFS are very different. The answer to Q4 is partly wrong: inner separators are not touched here, only leading and trailing ones. –  Gilles Dec 14 '11 at 12:06
2  
@Gilles: In Q2 none of the three given denominations refers to an unset IFS, all of them mean IFS=. –  Stéphane Gimenez Dec 14 '11 at 13:00
    
@Gilles In Q2, I never said they were the same. And inner separators are touched, as shown here: IFS=' ' ; foo=( bar baz qux ) ; echo "${#foo[@]}". (Er, what? There should be multiple space delimiters in there, SO engine keeps on stripping them). –  Chris Down Dec 14 '11 at 16:05
    
@StéphaneGimenez, Chris: Oh, right, sorry about Q2, I misread the question. For Q4, we're talking about read; the last variable grabs everything that's left except for the last separator and leaves inner separators inside. –  Gilles Dec 15 '11 at 15:25

Q1: Yes. “Field splitting” and “word splitting” are two terms for the same concept.

Q2: Yes. If IFS is unset (i.e. after unset IFS), it is equivalent IFS being set to $' \t\n' (a space, a tab and a newline). If IFS is set to an empty value (that's what “null” means here) (i.e. after IFS= or IFS='' or IFS=""), no field splitting is performed at all (and $*, which normally uses the first character of $IFS, uses a space character).

Q3: If you want to have the default IFS behavior, you can use unset IFS. If you want to set IFS explicitly to this default value, you can put the literal characters space, tab, newline in single quotes. In ksh93, bash or zsh, you can use IFS=$' \t\n'. Portably, if you want to avoid having a literal tab character in your source file, you can use

IFS=" $(echo t | tr t \\t)
"

Q4: With IFS set to an empty value, read -r line sets line to the whole line except its terminating newline. With IFS=" ", spaces at the beginning and at the end of the line are trimmed. With the default value of IFS, tabs and spaces are trimmed.

share|improve this answer
1  
Q2 is partly wrong. If IFS is empty, "$*" is joined without separators. (for $@, there are some variations between shells in non-list contexts like IFS=; var=$@). It should be noted that when IFS is empty, no word splitting is perfomed but $var still expands to no argument instead of an empty argument when $var is empty, and globbing still applies, so you still need to quote variables (even if you disable globbing) –  Stéphane Chazelas Feb 8 '13 at 22:19

unset IFS does clear IFS, even if IFS is thereafter presumed to be " \t\n":

$ echo "'$IFS'"
'   
'
$ IFS=""
$ echo "'$IFS'"
''
$ unset IFS
$ echo "'$IFS'"
''
$ IFS=$' \t\n'
$ echo "'$IFS'"
'   
'
$

Tested on bash versions 4.2.45 and 3.2.25 with the same behavior.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.