What is the difference having double quotes or not in bash

7,177

Solution 1

The main difference is that the quoted version is not subject to field splitting by the shell.

With double quotes the outcome of the command expansion would be fed as one parameter to the source command. Without quotes it would be broken up into multiple parameters, depending on the value of IFS which contains space, TAB and newline by default.

If the directory name does not contain such spaces then field splitting does not occur.

As a rule of thumb, it is best to use double quotes with command substitutions and variable expansions.

Solution 2

Without quotes the string is subject to word splitting and globbing. See also BashPitfalls #14.

Compare

$ echo $(printf 'foo\nbar\nquux\n*')
foo bar quux ssh-13yzvBMwVYgn ssh-3JIxkphQ07Ei ssh-6YC5dbnk1wOc 

with

$ echo "$(printf 'foo\nbar\nquux\n*')"
foo
bar
quux
*

When word splitting occurs the first character of IFS acts as a separator (which, per default, is a space).

In almost all situations you want to add quotes. There are a few exceptions, e.g.

  • In expressions where word splitting/globbing does not occur, for example simple (non-array) assignments and the case statement. The following are all safe:

    • foo=*
    • foo=${bar}qux${quux}
    • foo=$(bar "${quux}")
    • case ${var} in

    This, however, is not (if what you are after is a single element with a literal asterisk character):

    • foo=( * )
  • When you specifically want word splitting to occur, e.g. looping over the tokens in a whitespace-delimited string (with globbing disabled). However - if possible, use an array.

Solution 3

The likely most important difference would be if the directory that the script is in has a space in it. In that case, the first line, the one without the double-quotes, would fail. This would be the result of "word splitting" which bash does on unquoted strings.

Suppose that the result of dirname ${BASH_SOURCE[0]} is /home/j r/bin. Consider the line without quotes:

source $(dirname ${BASH_SOURCE[0]})/script.sh

In this case, bash will see the command:

source /home/j r/bin/script.sh

After word splitting, the source command sees a script name, /home/j and an argument to the script, r/bin/script.sh. Very likely, there is no script by that name and bash will return the error message:

bash: /bin/j: No such file or directory

Now consider what happens with double quotes:

source "$(dirname ${BASH_SOURCE[0]})/script.sh"

In this case, the source command will look for a script named /home/j r/bin/script.sh and try to source it.

For completeness, let's consider single-quotes:

source '$(dirname ${BASH_SOURCE[0]})/script.sh'

In this case, unlike the previous two, dirname is never executed. The source command will try to source a command with the literal name $(dirname ${BASH_SOURCE[0]})/script.sh. There is likely no such file and bash will emit an error message.

How bash treats strings in double quotes is described in full detail in man bash:

  Enclosing characters in double quotes preserves the  literal  value  of
   all  characters  within the quotes, with the exception of $, `, \, and,
   when history expansion is enabled, !.  The characters $  and  `  retain
   their  special meaning within double quotes.  The backslash retains its
   special meaning only when followed by one of the following  characters:
   $,  `,  ", \, or <newline>.  A double quote may be quoted within double
   quotes by preceding it with a backslash.  If enabled, history expansion
   will  be  performed  unless an !  appearing in double quotes is escaped
   using a backslash.  The backslash preceding the !  is not removed.
Share:
7,177

Related videos on Youtube

user3185306
Author by

user3185306

Updated on September 18, 2022

Comments

  • user3185306
    user3185306 over 1 year

    I have some bash scripts, one which has the following content:

    #!/bin/bash
    source $(dirname ${BASH_SOURCE[0]})/script.sh
    

    while the other one has the following content:

    #!/bin/bash
    source "$(dirname ${BASH_SOURCE[0]})/script.sh"
    

    How do these scripts behave differently and why? What is the difference?

  • helpermethod
    helpermethod about 10 years
    +1 For mentioning globbing. This bit me more than once.