A StackOverflow answer with > 3.5K votes features this one-liner for assigning to DIR
the directory of the current bash script:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
I'm puzzled by the nested double-quotes. As far as I can tell, the following fragments are double-quoted:
"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"
…and everything else to the right of the =
(i.e. $( dirname
and )
) is unquoted. In other words, I assume that the 2nd, 4th, and 6th "
characters "close" the 1st, 3rd, and 5th "
characters, respectively.
I understand what the double-quotes in "${BASH_SOURCE[0]}"
achieve, but what's the purpose of the other two pairs of double-quotes?
If, on the other hand (and the high vote score notwithstanding), the above snippet is incorrect, what's the right way to achieve its nominal intent?
(By nominal intent I mean: collect the value returned by pwd
after first cd
-ing to the directory returned by dirname "${BASH_SOURCE[0]}"
, and do the cd
-ing in a sub-shell, so that the $PWD
of the parent shell remains unchanged).
Best Answer
Your puzzle isn't right about how
bash
(and the shell in general) parsed the input. In:First,
bash
parse the right hand side of assignment to one long string$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
because double quote can appear inside double quotes.After then,
bash
start parsing the command substitution. Because all characters following open parenthesis to enclosing parenthesis are used to construct the command inside command substitution, you will get:The shell continue parsing that compound command, break it into two parts:
cd "$( dirname "${BASH_SOURCE[0]}" )"
Then applying the same parsing rule for
cd "$( dirname "${BASH_SOURCE[0]}" )"
, but this time, double quotes are not redundant, but make sense. They prevent field splitting on result of$( dirname "${BASH_SOURCE[0]}" )
, and also the expansion of${BASH_SOURCE[0]}
(In contrast with the outer most double quotes, will are not necessary in RHS of variable assignment to preventsplit+glob
).This rule apply to command substitution in all POSIX shell. A more details puzzle you can read in Token Recognition section of POSIX spec.