What is the exact meaning of IFS=$'\n'?
BashShellVariablesEnvironment VariablesIfsBash 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
IFS
?
What is 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.