What is command substitution in a shell?
"Command substitution" is the name of the feature of the shell language that allows you to execute a command and have the output of that command replace (substitute) the text of the command.
There is no other feature of the shell language that allows you to do that.
A command substitution, i.e. the whole $(...)
expression, is replaced by its output, which is the primary use of command substitutions.
The command that the command substitution executes, is executed in a subshell, which means it has its own environment that will not affect the parent shell's environment.
Not all subshell executions are command substitutions though (see further examples at end).
Example showing that a command substitution is executed in a subshell:
$ s=123
$ echo "hello $( s=world; echo "$s" )"
hello world
$ echo "$s"
123
Here, the variable s
is set to the string 123
. On the next line, echo
is invoked on a string containing the result of a command substitution. The command substitution sets s
to the string world
and echoes this string. The string world
is the output of the command in the command substitution and thus, if this was run under set -x
, we would see that the second line above would have been expanded to echo 'hello world'
, which produces hello world
on the terminal:
$ set -x
$ echo "hello $( s=world; echo "$s" )"
++ s=world
++ echo world
+ echo 'hello world'
hello world
(bash
adds an extra level of +
prompts to every level of a command substitution subshell in the trace output, other shells may not do this)
Lastly, we show that the command inside the command substitution was run in its own subshell, because it did not affect the value of s
in the calling shell (the value of s
is still 123
, not world
).
There are other situations where commands are executed in subshells, such as in
echo 'hello' | read message
In bash
, unless you set the lastpipe
option (only in non-interactive instances), the read
is executed in a subshell, which means that $message
will not be changed in the parent shell, i.e. doing echo "$message"
after the above command will echo an empty string (or whatever value $message
was before).
A process substitution in bash
also executes in a subshell:
cat < <( echo 'hello world' )
This too is distinct from a command substitution.