Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

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".

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top