What is the difference having double quotes or not in bash
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.
Related videos on Youtube
user3185306
Updated on September 18, 2022Comments
-
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 about 10 years+1 For mentioning globbing. This bit me more than once.