'\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 tostring
, 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.