What is the exact meaning of IFS=$'\n'?

BashShellVariablesEnvironment VariablesIfs

Bash Problem Overview


If the following example, which sets the IFS environment variable to a line feed character...

IFS=$'\n'
  • What does the dollar sign mean exactly?
  • What does it do in this specific case?
  • Where can I read more on this specific usage (Google doesn't allow special characters in searches and I don't know what to look for otherwise)?

I know what the IFS environment variable is, and what the \n character is (line feed), but why not just use the following form: IFS="\n" (which does not work)?

For example, if I want to loop through every line of a file and want to use a for loop, I could do this:

for line in (< /path/to/file); do
    echo "Line: $line"
done

However, this won't work right unless IFS is set to a line feed character. To get it to work, I'd have to do this:

OLDIFS=$IFS
IFS=$'\n'
for line in (< /path/to/file); do
    echo "Line: $line"
done
IFS=$OLDIFS

Note: I don't need another way for doing the same thing, I know many other already... I'm only curious about that $'\n' and wondered if anyone could give me an explanation on it.

Bash Solutions


Solution 1 - Bash

Normally bash doesn't interpret escape sequences in string literals. So if you write \n or "\n" or '\n', that's not a linebreak - it's the letter n (in the first case) or a backslash followed by the letter n (in the other two cases).

$'somestring' is a syntax for string literals with escape sequences. So unlike '\n', $'\n' actually is a linebreak.

Solution 2 - Bash

Just to give the construct its official name: strings of the form $'...' are called ANSI C-quoted strings.

That is, as in [ANSI] C strings, backlash escape sequences are recognized and expanded to their literal equivalent (see below for the complete list of supported escape sequences).

After this expansion, $'...' strings behave the same way as '...' strings - i.e., they're treated as literals NOT subject to any [further] shell expansions.

For instance, $'\n' expands to a literal newline character - which is something a regular bash string literal (whether '...' or "...") cannot do.[1]

Another interesting feature is that ANSI C-quoted strings can escape ' (single quotes) as \', which, '...' (regular single-quoted strings) cannot:

echo $'Honey, I\'m home' # OK; this cannot be done with '...'

List of supported escape sequences:

> Backslash escape sequences, if present, are decoded as follows: > >\a >alert (bell) > >\b >backspace > >\e >\E >an escape character (not ANSI C) > >\f >form feed > >\n >newline > >\r >carriage return > >\t >horizontal tab > >\v >vertical tab > >\ >backslash > >' >single quote > >" >double quote > >\nnn >the eight-bit character whose value is the octal value nnn (one to three digits) > >\xHH >the eight-bit character whose value is the hexadecimal value HH (one or two hex digits) > >\uHHHH >the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHH (one to four hex digits) > >\UHHHHHHHH >the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHHHHHH (one to eight hex digits) > >\cx >a control-x character > >The expanded result is single-quoted, as if the dollar sign had not been present.


[1] You can, however, embed actual newlines in '...' and "..." strings; i.e., you can define strings that span multiple lines.

Solution 3 - Bash

From http://www.linuxtopia.org/online_books/bash_guide_for_beginners/sect_03_03.html:

> Words in the form "$'STRING'" are > treated in a special way. The word > expands to a string, with > backslash-escaped characters replaced > as specified by the ANSI-C standard. > Backslash escape sequences can be > found in the Bash documentation.found

I guess it's forcing the script to escape the line feed to the proper ANSI-C standard.

Solution 4 - Bash

Re recovering the default IFS- this OLDIFS=$IFS is not necessary. Run new IFS in subshell to avoid overriding the default IFS:

ar=(123 321); ( IFS=$'\n'; echo ${ar[*]} )

Besides I don't really believe you recover the old IFS fully. You should double quote it to avoid line breaking such as OLDIFS="$IFS".

Solution 5 - Bash

ANSI C-quoted strings is a key point. Thanks to @mklement0 .

You can test ANSI C-quoted strings with command od.

echo -n $'\n' | od -c
echo -n '\n' | od -c
echo -n $"\n" | od -c
echo -n "\n" | od -c

Outputs:

0000000  \n  
0000001

0000000   \   n   
0000002

0000000   \   n   
0000002

0000000   \   n   
0000002

You can know the meaning clearly by the outputs.

Solution 6 - Bash

Question:

What is the exact meaning of IFS=$'\n'?

Simple Answer:

Hey Bash! set the Internal Field Separator (IFS) to New Line


What is IFS ?

IFS is the character, Bash uses as word/item boundaries when processing character strings.

It is set to whitespace characters of space, tab, and newline, by default.

Example 1:

Use default value for IFS

string="first second:third forth:fifth"

for item in $string; do
	echo "$item"
done

Output:

first
second:third
forth:fifth

Example 2:

Set IFS to :

# Set the IFS to collon (:) character
IFS=:

string="first second:third forth:fifth"

for item in $string; do
	echo "$item"
done

Output:

first second  
third forth  
fifth

Solution 7 - Bash

It's like retrieving the value from a variable:

VAR='test'
echo VAR
echo $VAR

are different, so the dollar sign basically evaluates the content.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYanick GirouardView Question on Stackoverflow
Solution 1 - Bashsepp2kView Answer on Stackoverflow
Solution 2 - Bashmklement0View Answer on Stackoverflow
Solution 3 - BashBrad SwerdfegerView Answer on Stackoverflow
Solution 4 - BashMarekView Answer on Stackoverflow
Solution 5 - BashBig ShieldView Answer on Stackoverflow
Solution 6 - BashPmpr.irView Answer on Stackoverflow
Solution 7 - BashPieterView Answer on Stackoverflow