Double quotes for variable and command substitution
Variable substitutions should only be used inside double quotes.
calculation='2 * 3'
echo "$calculation" # prints 2 * 3
echo $calculation # prints 2, the list of files in the current directory, and 3
echo "$(($calculation))" # prints 6
Outside of double quotes, $var takes the value of var, splits it into whitespace-delimited parts, and interprets each part as a glob (wildcard) pattern. Unless you want this behavior, always put $var inside double quotes: $var“.
The same applies to command substitutions: “$(mycommand)” is the output of mycommand, $(mycommand) is the result of split+glob on the output.
echo "$var" # good
echo "$(mycommand)" # good
another=$var # also works, assignment is implicitly double-quoted
make -D THING=$var # BAD! This is not a bash assignment.
make -D THING="$var" # good
make -D "THING=$var" # also good
Command substitutions get their own quoting contexts. Writing arbitrarily nested substitutions is easy because the parser will keep track of nesting depth instead of greedily searching for the first ” character. The StackOverflow syntax highlighter parses this wrong, however. For example:
echo "formatted text: $(printf "a + b = %04d" "${c}")" # “formatted text: a + b = 000”
Variable arguments to a command substitution should be double-quoted inside the expansions as well:
echo "$(mycommand "$arg1" "$arg2")"
Difference between double quote and single quote
Double quote | Single quote |
Allows variable expansion | Prevents variable expansion |
Allows history expansion if enabled | Prevents history expansion |
Allows command substitution | Prevents command substitution |
and @ can have special meaning | and @ are always literals |
Can contain both single quote or double quote | Single quote is not allowed inside single quote |
$, `, “, \ can be escaped with \ to prevent their special meaning All of them are literals |
Properties that are common to both:
- Prevents globbing
- Prevents word splitting
Examples:
$ echo "!cat"
echo "cat file"
cat file
$ echo '!cat'
!cat
echo "\"'\""
"'"
$ a='var'
$ echo '$a'
$a
$ echo "$a"
var
Newlines and control characters
A newline can be included in a single-string or double-quoted string. Note that backslash-newline does not result in
a newline, the line break is ignored.
newline1='
'
newline2="
"
newline3=$'\n'
empty=\
echo "Line${newline1}break"
echo "Line${newline2}break"
echo "Line${newline3}break"
echo "No line break${empty} here"
Inside dollar-quote strings, backslash-letter or backslash-octal can be used to insert control characters, like in many
other programming languages.
echo $'Tab: [\t]'
echo $'Tab again: [\009]'
echo $'Form feed: [\f]'
echo $'Line\nbreak'
Quoting literal text
All the examples in this paragraph print the line
!"#$&'()*;<=>? @[\]^`{|}~
A backslash quotes the next character, i.e. the next character is interpreted literally. The one exception is a newline:
backslash-newline expands to the empty string.
echo \!\"\#\$\&\'\(\)\*\;\<\=\>\?\ \ \@\[\\\]\^\`\{\|\}\~
All text between single quotes (forward quotes ‘, also known as apostrophe) is printed literally. Even backslash
stands for itself, and it’s impossible to include a single quote; instead, you can stop the literal string, include a literal
single quote with a backslash, and start the literal string again. Thus the 4-character sequence ‘\” effectively allow
to include a single quote in a literal string.
echo '!"#$&'\''()*;<=>? @[\]^`{|}~'
# ^^^^
Dollar-single-quote starts a string literal $’…’ like many other programming languages, where backslash quotes the
next character.
echo $'!"#$&\'()*;<=>? @[\\]^`{|}~'
# ^^ ^^
Double quotes ” delimit semi-literal strings where only the characters ” \ $ and ` retain their special meaning.
These characters need a backslash before them (note that if backslash is followed by some other character, the
backslash remains). Double quotes are mostly useful when including a variable or a command substitution.
echo "!\"#\$&'()*;<=>? @[\\]^\`{|}~"
# ^^ ^^ ^^
echo "!\"#\$&'()*;<=>? @[\]^\`{|}~"
# ^^ ^ ^^ \[ prints \[
Interactively, beware that ! triggers history expansion inside double quotes: “!oops” looks for an older command
containing oops; “!oops” doesn’t do history expansion but keeps the backslash. This does not happen in scripts.