I tend to quote command substitutions as shown below even when assigning their output to a variable:
var="$(command)"
Is that actually needed though? When does it break? The accepted answer here claims:
DIRNAME="$(dirname $FILE)" will not do what you want if $FILE contains whitespace or globbing characters [?*.
The link points to Grey Cat Wiki's great page about quoting but that page doesn't mention quoting command substitutions specifically. And while quoting the variable is clearly needed, quoting the command substitution itself doesn't seem to be.
However, the same post concludes with:
DIRNAME="$(dirname "$FILE")" is the recommended way. You can replace DIRNAME= with a command and a space without changing anything else, and dirname receives the correct string.
Which is what I've always thought as well and have often corrected posts here that didn't quote it. However, the wiki page linked to above also claims that:
There are a few cases where double quotes may be safely omitted:
On the right-hand side of a simple assignment. You may write foo=$bar without quotes. This is POSIX compliant.
[. . . ]
While var=$(command)
isn't really a "simple" assignment, I was nevertheless unable to find a case where the quotes were actually necessary:
$ var=$(echo "foo bar baz") ## whitespace works
$ echo "$var"
foo bar baz
$ var=$(printf "foo\nbar * baz") ## so do globbing characters
$ echo "$var"
foo
bar * baz
$ var1="foo\nbar * baz"
$ var=$(printf "$var1") ## printing a variable doesn't make any difference
$ echo "$var"
foo
bar * baz
$ var=$(printf '%s\n' "$var1")
$ echo "$var"
foo\nbar * baz
$ var=$(printf -- '-e %s\n' "$var1") ## strings starting with - also work
$ echo "$var"
-e foo\nbar * baz
Of course, the quotes are absolutely necessary if the command substitution is being used directly for things like command1 "$(command2)"
, but that doesn't seem to be the case when assigning to a variable.
So, what am I missing? Are the quotes ever needed? What corner case will quoting a command substitution when assigning its return value to a variable protect you from? Or is it always OK to not quote a command substitution if it is the right-hand side of a variable assignment operation?
var=$(command)
is not a simple assignment then var=$foo and var=${foo} are also not simple assignments. Only var="foo bar" is really simple. But you can only omit the quotes if the expression on the right side is a shell evaluation like$(...)
or${...}
– rudimeier Apr 29 '17 at 15:44var=$(command)
should indeed be considered "simple" but that's precisely what I'm asking: are there any cases where the quotes would be necessary? – terdon Apr 29 '17 at 15:50DIRNAME="$(dirname "$FILE")"
is the recommended way and that is the claim I am asking about. In any case, that question is about quoting within command substitutions and only mentions quoting the substitution itself in passing, so I felt we could have a better answer specifically dealing with quoting the$()
. – terdon Apr 29 '17 at 15:56var="$(command)"
is superfluous even if there be white space characters.var=$(command)
is absolutely the way to go and there are NO corner cases here. Where quotes are needed are when used as in:var="$(command)" myScript arg1 arg2 ...
– Apr 29 '17 at 16:01recommends
only to avoid bugs if your change that script later: "You can (later) replace DIRNAME= with a command and a space without changing anything". – rudimeier Apr 29 '17 at 16:03var=$(command) myScript arg1 arg2 ...
– enzotib Apr 29 '17 at 16:13echo '' | awk -v var=$(echo a b) '{print var}'
gives an error unless var is quoted. – Apr 29 '17 at 16:22awk
command – enzotib Apr 29 '17 at 16:25