$(…)
is a command substitution (“process substitution” is <(…)
and the like). Variable substitutions and command substitutions occur in the same pass, from left to right in the string. The only things that occur on the result of these substitutions are word splitting and globbing.
So x='$(id)'
sets x
to the 5-character string $(id)
. Then, to run $x
, the shell replaces $x
by the value $(id)
. This does not contain any whitespace or globbing character so it is treated as a command name.
Contrast with:
x='@(id)'
shopt -s extglob
echo /none/$x /usr/bin/$x
Assuming that the file /none/id
doesn't exist but /usr/bin/id
does, the echo
command expands to three words: echo
(obviously), /none/@(id)
(the glob pattern /none/@(id)
doesn't match anything so it's left unchanged), and /usr/bin/id
(the glob pattern /usr/bin/@(id)
matches one file, so it's replaced by the one-element list of matches).
In the bash manual, the relevant sentence is at the beginning of the Shell Expansions section.
The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and filename expansion.
Everything between two semicolons is one pass. Each pass works on the result of the previous pass.
Beware that a single sentence (even a complex one like the one I cited above) can't tell the whole story. Shell semantics is convoluted. I doubt that any shell's manual has the details of all the corner cases. The POSIX specification is more formal but doesn't cover bash-specific extensions and even it leaves some really odd cases undefined.
$x
and does not reconsider the$(id)
, but would like to back it up with references to sources before answering. Notice the careful semicolon & comma punctuation at https://www.gnu.org/savannah-checkouts/gnu/bash/manual/html_node/Shell-Expansions.html#Shell-Expansions where it says "The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and filename expansion." – Jeff Schaller Oct 21 '21 at 14:10$x
, to expand it to$(id)
and expand it again to the output ofid
: the shell never re-parses the result of an expansion in search for further expansion-triggering characters. More on this here - an answer of mine to a different question (I am unable to find a better reference at the moment). – fra-san Oct 21 '21 at 14:14$
. Consider that a filename likeA $2.00 thingy
might otherwise trigger expansion of the second positional parameter (or command line argument) via the$2
there, probably referring to a different filename. And files called$(rm -rf $HOME)
would be far worse... – ilkkachu Oct 21 '21 at 14:23