14

I notice that to set newline IFS should with a $ as prefix

IFS=$'\n'

but if set a colon, just

IFS=:

Is \n is a variable?

3 Answers 3

22

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 / \U0000000a for the characters with the corresponding Unicode code point. 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).

1
  • 1
    +1 for the usual inhuman level of knowledge
    – Zombo
    Oct 27, 2018 at 23:38
10

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

6

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.

4
  • The $'...' expansions differ from that of echo. They're more like the ones for the format argument of printf. For echo, a 0 is required in \0123 while for $'...' and printf format, \0123 would be \012 a newline followed by a litteral 3. Oct 26, 2018 at 12:48
  • 1
    Note that the $'...' specification is still being discussed. There are several issues still to be resolved with the currently proposed wording. Oct 26, 2018 at 12:53
  • IIRC, It was closed but has been reopened. Due to the fact that there is still plenty of time before it becomes effective, I don't see a real problem with that.
    – schily
    Oct 26, 2018 at 12:54
  • 1
    It was closed, I raised several objections, it was reopen, it was then amended, there are still several problems (most of them about \uxxxx expansion), and no resolution in sight that would accommodate existing implementations. So it may not make it into the next POSIX version. Maybe they could leave the \uxxxx expansion out for issue8, so we can still have at least $'\n'. Oct 26, 2018 at 13:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .