Background
This [ article ] says :
The command substitution expands to the output of commands. These commands are executed in a subshell ..
But the bash manual says nothing about a subshell
in its command substitution section.
My test below
$ ps
PID TTY TIME CMD
26483 pts/25 00:00:00 bash
26866 pts/25 00:00:00 ps
$ hpid="$(ps | grep bash)"
$ echo "$hpid"
26483 pts/25 00:00:00 bash
26899 pts/25 00:00:00 bash
shows that a new shell with pid 26899 was spawned during the command substitution. At this point I changed the PATH
environment variable.
$ PATH="/some/rogue/path"
did the below stuff :
VAR="$(echo "Do|Die" | cut -d"|" -f 2)"
and got the below error :
Command 'cut' is available in '/usr/bin/cut'
The command could not be located because '/usr/bin' is not included in the PATH environment variable.
cut: command not found
I understand that the error is due to the modification of PATH environment variable which helps the shell locate the binaries. However I am confused when reading this together with command substitution.
If by $(..)
a subshell is spawned, then PATH environment variable should be intact and should point to the binary (cut
in this case) and so bash should not complain that it cannot locate the cut
binary.
Question
How did the modification of the PATH
affect the command substitution here?
Consider below example:
$ export PS1='\$\$=$$ \$ '
$$=30862 $ a=123 # Note: No export a here.
$$=30862 $ echo $a
123
$$=30862 $ bash
$$=31133 $ echo $a # Subshell explicitly created does not have it.
$$=31133 $ exit
$$=30862 $ echo $(eval 'echo $a') # This subshell however does inherit it. The single quote ensures that this is not evaluated by parent shell.
123 # echo $(echo $a) would probably cause $a to be evaluated by parent shell.
$$=30862 $
In short, subshells spawned by $(...)
inherit same environment as parent shell, even if the variable is not exported. (Even $$
is same as parent shell.)