'\n' in `IFS=$'\n' is a variable?

That $'...' in bash is not parameter expansion, it's a special kind of quote introduced by ksh93 that expands those \n, \x0a, \12 codes to a newline character. zsh also added \u000a. ksh93 and bash also have \cj while zsh has \C-J. ksh93 also supports variations like \x{a}.

The $ is a cue that it is some form or expansion. But in any case, it differs from other forms of expansions that use $ (like $((1 + 1)), $param or $(cmd)) in that it is not performed inside double quotes or here documents (echo "$'x'" outputs $'x' in all shells though is unspecified per POSIX) and its expansion is not subject to split+glob, it's definitely closer to a quoting operator than an expansion operator.

IFS=\n would set IFS to n (\ is treated as a quoting operator) and IFS="\n" or IFS='\n' would set IFS to the two characters backslash and n.

You can also use:

IFS='
'

or

IFS="
"

or

IFS=$'
'

To pass a literal newline, though that's less legible (and one can't see other than using things like set list in vi whether $IFS contains other spacing characters in that code).

IFS=:, IFS=':', IFS=":", IFS=$':' all set IFS to : so it doesn't matter which you use.

$'...' is supported (with variations) by at least: ksh93, zsh, bash, mksh , busybox sh, FreeBSD sh. ksh93 and bash also have a $"..." form of quotes used for localisation of text though it's rarely used as it's cumbersome to deploy and use portably and reliably.

The es and fish shells can also use \n outside of quotes to expand to newline.

Some tools like printf, some implementations of echo or awk can also expand those \n by themselves. For instance, one can do:

printf '\n'
awk 'BEGIN{printf "\n"}'
echo
echo '\n\c' # UNIX compliant echos only

to output of newline character, but note that:

IFS=$(printf '\n')

won't work because command substitution ($(...)) strips all trailing newline characters. You can however use:

eval "$(printf 'IFS="\n"')"

Which works because the output of printf ends in a " character, not a newline.

Now, for completeness, in the rc shell and derivatives (like es or akanga), $'\n' is indeed the expansion of that \n variable (a variable whose name is the sequence of two characters \ and n). Those shells don't have a limitation on what characters variable names may contain and only have one type of quotes: '...'.

$ rc
; '\n' = (foo bar)
; echo $'\n'
foo bar
; echo $'\n'(1)
foo

rc variables are also all exported to the environment, but at least in the Unix variant of rc, for variable names like \n, the environment variable version undergoes a form of encoding:

; env | grep foo | sed -n l
__5cn=foo\001bar$

(0x5c being the byte value of ASCII \; see also how that array variable was encoded with a 0x1 byte as the separator).


This is ANSI-C quoting:

Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard.

Thus $'\n' is replaced by a newline.

This is unrelated to shell parameter expansion, despite the use of $.


Strings like $'\n' have been introduced by ksh93 and are currently not part of the POSIX standard.

They allow to use most C alike escapes, e.g. $'\u2345' and the escapes that are also supported by echo.

Note that if you do not like (in case of ksh93 or bash) to use that escape method, you still may use:

IFS='
'

which is equivalent but harder to read.

BTW: This extension already has passed the POSIX standard commitee, but it is scheduled for SUSv8 that is expected to appear not before the year 2020 because we first need to work on our lag behind the current list of bugs.

Tags:

Bash