Search code examples
bashshellscriptingsubshell

Bash command substitution + parameter expansion


I'm confused how the quoting and parameter and glob expansion is supposed to work in a subshell. Does the quoting and expansions of the subshell command line always happen in the context of the subshell process? My test seems to confirm this.

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ ls
a  b  c

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ echo "$(echo *)"
a b c
# The subshell expands the * glob

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ echo $(echo '*')
a b c
# The subshell outputs literal *, parent shell expands the * glob

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ echo $(echo "*")
a b c
# The subshell outputs literal *, parent shell expands the * glob

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ echo "$(echo '*')"
*
# The subshell outputs literal *, parent shell outputs literal *

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ foo=bar

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ echo "$(echo $foo)"
bar
# The subshell expands variable foo

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ echo $(echo '$foo')
$foo
# The subshell outputs literal $foo

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ echo $(echo "$foo")
bar
# The subshell expands variable foo

Tuomas@DESKTOP-LI5P50P MINGW64 ~/shell/test1/test
$ echo "$(echo '$foo')"
$foo
# The subshell outputs literal $foo

Am I correct? Is there any scenarios, where parents shell will somehow process or evaluate the subshell command line before forking?


Solution

  • The parsing -- thus, the determination of which content is quoted how -- happens before the fork. Because the forked-off copy of the shell has a copy-on-write instance of the memory of its parent process, it also has the parse tree, and inherits this information from its parent.

    The parameter expansion (of $foo in your examples) happens after the fork. Similarly, the contents of foo are first string-split and glob-expanded to generate an argument list to pass to echo inside the subshell. Then that subshell runs echo, and the output written to stdout is read by the parent process (the original shell).

    String-splitting and glob expansion of the command substitution's result (the content written by echo) happens back in the parent process, after it read the output of its child as a string.