What is the difference between the "...", '...', $'...', and $"..." quotes in the shell?
All of these mean something different, and you can write different things inside them (or the same things, with different meaning). Different kinds of quote interpret different escape sequences inside them (\something
), or do or don't allow variable interpolations ($something
) and other sorts of expansion inside them.
In short:
-
'...'
is entirely literal. -
"..."
allows both variables and embedded quote characters. -
$'...'
performs character escapes like\n
, but doesn't expand variables. -
$"..."
is for human-language translations in Bash and ksh.
'Single quotes'
Whatever you write between single quotes is treated literally and not processed at all. Backslashes and dollar signs have no special meaning there. This means you can't backslash-escape a character (including other single quotes!), interpolate a variable, or use any other shell feature.
All of these examples result in literally what's written between the quotes:
Code | Result |
---|---|
'hello world' |
hello world |
'/pkg/bin:$PATH' |
/pkg/bin:$PATH |
'hello\nworld' |
hello\nworld |
'`echo abc`' |
`echo abc` |
'I\'dn\'t've' |
I\dn'tve |
The last one is complicated - there are two single-quoted strings run together with some unquoted text. The first one contains I\
. The unquoted text dn\'t
contains a single quote that's escaped at the shell level, so it doesn't start a quoted string and is included as a literal character (so, dn't
). The final quoted string is just ve
. All of those get run together into a single word in the usual way the shell works.
A somewhat-common idiom for combining literal text and variables is to run them together like that:
'let x="'$PATH\"
will result in
let x="/usr/bin:/bin"
as a single word (better to double-quote $PATH
as well just in case - spaces or globbing characters in the variable value may be processed otherwise - but for the sake of a readable running example I haven't).
"Double quotes"
Inside double quotes, two sorts of expansion are processed, and you can use a backslash to escape characters to prevent expansions or escapes from being processed.
There are two categories of expansion that happen inside double quotes:
- Those starting with
$
(parameter expansion$abc
and${abc}
, command substitution$(...)
, and arithmetic expansion$((...))
); - Command substitution with backquotes
`abc`
;
Inside the quotes, a backslash can inhibit those expansions by putting it before the $
or `
. It can also escape a closing double quote, so \"
includes just "
in your string, or another backslash. Any other backslash is preserved literally - there are no escapes to produce other characters, and it isn't removed.
Some of these examples act differently to before, and some don't:
Code | Result |
---|---|
"hello world" |
hello world |
"/pkg/bin:$PATH" |
/pkg/bin:/bin:/usr/bin |
"hello\nworld" |
hello\nworld |
"hello\\nworld" |
hello\nworld |
"`echo abc`" |
abc |
"I\'dn\'t've" |
I\'dn\'t've |
"I'dn't've" |
I'dn't've |
"I\"dn\"t've" |
I"dn"t've |
$'ANSI-C quoting'
This kind of quoting allows C-style backslash escapes to be processed, but not embedded variables or substitutions. It's the only kind of quoting that supports character escapes.
This is an extension from ksh, now supported in Bash, zsh, and some other shells as well. It is not yet part of the POSIX standard and so maximally-portable scripts can't use it, but a Bash or ksh script is free to.
All of these escapes can be used with their C meanings: \a
, \b
, \f
, \n
, \r
, \t
, \v
, and the literal escapes \\
, \'
, \"
, and \?
. They also support the extensions \e
(escape character) and in Bash and ksh \cx
(what would be entered by Ctrl-x, e.g. \cM
is carriage return). Shells have a range of minor extensions of their own.
It also allows four kinds of generic character escapes:
-
\nnn
, a single byte with octal value nnn -
\xHH
, a single byte with hexadecimal value HH -
\uHHHH
, the Unicode codepoint whose hexadecimal index is HHHH -
\UHHHHHHHH
, the Unicode codepoint whose hexadecimal index is HHHHHHHH
All of those digits are optional after the first one.
$
and `
have no meaning and are preserved literally, so you can't include a variable there.
Code | Result |
---|---|
$'hello world' |
hello world |
$'/pkg/bin:$PATH' |
/pkg/bin:$PATH |
$'hello\nworld' |
hello world |
$'`echo abc`' |
`echo abc` |
$'I\'dn\'t\'ve' |
I'dn't've |
$'\U1f574\u263A' |
🕴☺ |
Most of these escapes you can simulate using the printf
command, though POSIX only requires \\
, \a
, \b
, \f
, \n
, \r
, \t
, \v
, and \nnn
to work there. You can use command substitution to embed a printf
inside double quotes if needed: "Path:$(printf '\t')$PATH"
.
$"Locale translation"
This is a ksh- and Bash-specific extension for localising natural-language textual strings, and looks up the part inside the quotes in a message catalog. It performs all the double quote expansions first. If the string isn't found in the translation database, it's used as its own translation. The built-in assumption is that the strings are in English.
You probably don't want to use this one, but if you see it you can generally treat it as regular double quotes.
One point of note is that there is no kind of quoting that allows both embedded parameter expansion and embedded character escapes. In most cases where you would want that, you'd be better off (safer) using printf
:
printf 'New path: \e[1m%s\e[0m' "/pkg/bin:$PATH:"
This clearly separates which parts are subject to character escaping and which are data values.
Another is that all of these styles of quoting create a single "word" in the shell, unless $@
or an array expansion ${x[@]}
is used inside double quotes. Both single-quote forms are always one word and never expanded any further.
Related videos on Youtube
Michael Homer
Updated on September 18, 2022Comments
-
Michael Homer over 1 year
Sometimes I see shell scripts use all of these different ways of quoting some text:
"..."
,'...'
,$'...'
, and$"..."
. Why are there so many different kinds of quote being used?Do they behave differently or affect what I can do inside them?
-
chepner about 5 yearsPossible cross-site duplicate. This answer provides a summary of (or links to) the semantics of all the different types of quotes.
-
Stéphane Chazelas about 5 years
-
-
Stéphane Chazelas about 5 years
$"..."
is also from ksh93, added to bash in 2.0. -
Stéphane Chazelas about 5 yearsThere's no
\cX
inzsh
. It's\CX
or\C-X
there (\c
already has a special meaning inecho
) -
Stéphane Chazelas about 5 years
'let x="'$PATH\"
is wrong in list contexts in shells other thanzsh
as$PATH
is not quoted (so would be subject to split+glob which you wouldn't want here). -
Stéphane Chazelas about 5 yearsYou may want to clarify that you're talking of Korn-like shells, quote processing is different in csh, rc, fish...
-
done about 5 years@StéphaneChazelas Define "list context".