3

I know single quotes will not evaluate what's inside, and double quotes will. I often see people quote-quote the dollar sign evaluation. Here are some examples:

  • for i in "${indices[@]}"; do
  • if [ "${a}" == 0 ]; then
  • ffmpeg -framerate 2 -pattern_type glob -i "*.png" -pix_fmt yuv420p output.mp4

What if we don't double-quote the dollar sign expression? AFAIK, the for loop still works.

  • 3
    It is related to something known as word splitting. Without double quotes , varialbe which has 'hello world' stored inside will be treated as two separate items.With double quotes, it will be treated as one item. Very often word splitting is not what you as programmer want and cases where you want to avoid double quotes are rare – Sergiy Kolodyazhnyy Feb 23 '17 at 17:36
  • there are duplicate questions on this site, but i am on mobile and cant provide one right now – Sergiy Kolodyazhnyy Feb 23 '17 at 17:36
  • 2
    Related: http://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable-in-bash-posix-shells – Kusalananda Feb 23 '17 at 17:43

2 Answers2

6

Your three examples are not all exactly alike.

In the last two:

if [ "${a}" == 0 ]; then
ffmpeg -framerate 2 -pattern_type glob -i "*.png" -pix_fmt yuv420p output.mp4

If $a was not quoted, and its value contained characters of $IFS (by default space, tab and newline) or wildcard characters, this would cause [ to receive more than three arguments (beside the [ and ] ones), resulting in an error; similarly, if the value of $a was the empty string, this would cause [ to receive too few arguments:

$ (a=0; [ $a == 0 ] && echo OK)
OK

(but only if $IFS currently happens not to contain 0)

$ (a='foo bar'; [ $a == 0 ] && echo OK)
bash: [: too many arguments

(with the default value of $IFS)

$ (a=; [ $a == 0 ] && echo OK)
bash: [: ==: unary operator expected

(even with an empty $IFS or with zsh (that otherwise doesn't implement that implicit split+glob operator upon unquoted expansions))

$ (a='*'; [ $a == 0 ] && echo OK)
bash: [: too many arguments

(when run in a directory that contain at least 2 non-hidden files).

With quoting, no error:

$ (a='foo bar'; [ "$a" == 0 ] && echo OK)
$ (a=; [ "$a" == 0 ] && echo OK)

Your first example is different. The rules about expansion within double quotes are special when arrays are involved; if a denotes an array, then:

  • $a is the first element of the array (sticktly speaking it's ${a[0]} even if the element at indice 0 is not defined);

  • ${a[*]} or ${a[@]} are the elements of the array, additionally split at $IFS (space, tab, newline by default);

  • "${a[@]}" is the elements of the array, not split at $IFS.

So your loop for i in "${indices[@]}"; do ... does not actually work the same, depending on the contents of the array. For example:

$ (declare -a a=(a b c); printf '%s\n' $a)
a

$ (declare -a a=(a b c); printf '%s\n' ${a[*]})
a
b
c

$ (declare -a a=(a 'b c'); printf '%s\n' ${a[*]})
a
b
c

$ (declare -a a=(a 'b c'); printf '%s\n' ${a[@]})
a
b
c

$ (declare -a a=(a 'b c'); printf '%s\n' "${a[*]}")
a b c

$ (declare -a a=(a 'b c'); printf '%s\n' "${a[@]}")
a
b c
dhag
  • 15,736
  • 4
  • 55
  • 65
2

Long story made short, this is done to avoid expansions made by special characters that could be inside the variable, like !. Double quotes are also called "weak quoting", since some of the characters will be interpreted(dollar sign, backquote and backslash). Single quotes are "strong quoting" and nothing will be interpreted.

Quoting bash documentation:

3.1.2.3 Double Quotes

Enclosing characters in double quotes (") preserves the literal value of all characters within the quotes, with the exception of $, backquote, \, and, when history expansion is enabled, !. When the shell is in POSIX mode (see Bash POSIX Mode), the ! has no special meaning within double quotes, even when history expansion is enabled...

Examples of weak and strong quoting:

  • echo "Your PATH is: $PATH" - Will print Your PATH is:<variable_content>
  • echo 'Your PATH is: $PATH' - Will print Your PATH is: $PATH

Answering your question, we use double quotes with variables to allow $ to be expanded, but to avoid that the variable contents be further expanded.

Related Stuff:

  • That is misleading. ! and backslash are not a problem by default in cmd $var when found in $var in bash. It's wildcard characters and characters of $IFS – Stéphane Chazelas Feb 24 '17 at 09:36