Many different types of quotes enable different ways of interpreting their contents.
Unfortunately, the rules and their behavior varies by context with several special cases and exceptions to remember.
TIP: When in doubt, double-quote every expansion in your shell commands.
The basic rule of thumb is that you should double-quote every expansion. This prevents unwanted word splitting and globbing.
There are a few cases where double quotes may be safely omitted:
foo=$bar
case $foo in ...
[[ -z $string ]]
WARNING: However, be warned that quoted and unquoted can act differently. The [[ keyword is a Bash extension.
[[ foo = $bar ]] and [[ foo = "$bar" ]]
These do act differently.
Use single quotes when protecting complex strings, especially ones that contain shell syntax which you don't want evaluated.
There are 3 types of quotes. Each of the quotes bring different meaning and usage.
' (single quotes) - Everything wrapped in this quote won't be changed (Strong quotes) " (double quotes) - Quotes that doesn't expand meta-characters like "*" or "?," but does expand variables and does command substitution (Weaker quotes) ` (back quotes) - To execute command. The legacy command substitution syntax; deprecated in favor of **$(...)** but still permitted for historical reasons.
Putting a backslash character \ in front of a quote removes its special meaning.
This works inside double quotes, or in the absence of quotes.
It does not work inside single quotes.
echo 'Don'\''t walk!' echo "Don't walk!" echo $'Don\'t talk!'
$(…)-style command substitutions are unique in that the quoting of their contents is completely independent to their surroundings. This means you don't have to worry about nested quote escaping problems.
The various types of quotes can be combined, or concatenated, if needed.
For example, if you have one section of a string that has lots of special characters that you'd like to single-quote, and another section with a parameter expansion in it which must be double-quoted, you may mix them:
foo=bar echo '!%$*&'"$foo"
returns:
!%$*&bar
The result (after appropriate expansions in the double-quoted sections) is a single word.
NOTE: Any number of quoted substrings, of any style, may be concatenated in this manner.
Double-quoting $@ or ${array[@]} has a special meaning.
“$@” expands to a list of words, with each positional parameter's value being one word.
Likewise, “${array[@]}” expands to a list of words, one per array element.
When dealing with the positional parameters or with the contents of an array as a list of words, always use the double-quoted syntax.
Example of proper iteration over the positional parameters using a quoted “$@”. Never use an unquoted $@ or $*.
for file in "$@"; do ... done
Double-quoting $* or ${array[*]} results in one word which is the concatenation of all the positional parameters (or array elements) with the first character of IFS between them.
This is similar to the join function in some other languages, although the fact that you can only have a single join character can sometimes be a crippling limitation.
for index in "${array[@]}"; do ...
cp $file $destination # WRONG cp -- "$file" "$destination" # Right
In this example, the double quotes protect the value of each parameter from undergoing word splitting or globbing should it happen to contain whitespace or wildcard characters (* or ? or […]).
Without the quotes, a filename like hot stuff.mp3 would be split into two words, and each word would be passed to the cp command as a separate argument. or, a filename that contains * with whitespace around it would produce one word for every file in the current directory. That is not what we want.
With the quotes, every character in the value of the filename parameter is treated literally, and the whole value becomes the second argument to the cp command.
When in doubt, always double-quote your parameter expansions.
Example of using back quotes within single quotes. Nothing is changed.
echo 'Today is `date`' Today is `date`
Example of using back quotes within double quotes. The `date` command will be executed:
echo "Today is `date`" Today is Mon May 26 09:42:50 MYT 2008