Issue
I found that Bash does not expand a brace after $$.
$ echo $BASH_VERSION
5.1.16(1)-release
$ echo $${x,y}
4821{x,y} #not expanded (though $$ is evaluated.) ---> Why?!?!?!
How should I explain this behavior?
I have tried similar patterns as follows. I can understand them.
$ echo $?{x,y}
0x 0y #{x,y} is expanded.
$ echo ${$}{x,y}
4821x 4821y #expanded (We should write like this instead of $${x,y}.)
$ echo $PPID{x,y}
#not expanded (maybe parsed as a variable "PPID{x,y}")
Solution
Bash performs brace expansions before parameter expansions. Brace expansion does not do a full analysis of the syntax to be able to determine what is a brace expansion or not. It implements a simple rule the sequence ${
is not treated as brace expansion, even if it looks like it.
If ${a,b}
were allowed to produce $a $b
, it would mean that brace expansion has to analyze, in detail, every single instance of ${...}
syntax, in order to correctly detect brace expansions, and leave alone parameter expansions.
Now, the expansion does kick in if we escape the dollar sign: \${a,b}
. Then we get $a $b
(which are not treated as variables). So the real rule is actually subtle: if ${
occurs where the dollar sign is unescaped, then the brace is not scanned for race expansion.
This logic is not perfect, and making it perfect is fraught with pitfalls.
You cannot simply allow $${
because this could be part of a larger syntax which looks like $$${
, where the first two $$
are the PID, followed by ${
.
Quick, tell me, should this undergo brace expansion?
$$\$$$$$$$$$\$\$$$\$$$$$$$\$$$$$${a,b}
Trying to implement complex exceptions to the ${
rule would be a fool's errand. The correct solution would be for brace expansion to earnestly parse the syntax so that it accurately knows what is a braced parameter expansion and what isn't.
The workaround for this and related issues is to distribute one or more characters into your brace expansion.
That is to say:
$${a,b} -> {$$a,$$b}
Another case: say we have $a
and $b
variables that we want to expand, and we write ${a,b}
. That's not supported, and thus, we manually distribute the dollar sign into the brace expansion:
${a,b} -> {$a,$b}
In other cases we don't have to. If we have two variables $foobar
and $foobaz
, then the brace expansion $fooba{r,z}
will produce $foobar
and $foobaz
that then expand. When there is nothing between the $
and the {
, we need the workaround of distributing the $
sign.
For $$
, other workarounds are possible:
"$$"{a,b} # $$ is expanded inside double quotes, like all params
${$}{a,b} # The second $ can be braced, like a param name.
Answered By - Kaz Answer Checked By - Marie Seifert (WPSolving Admin)