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.