I'm reading the book "Linux Command Line and Shell Scripting Bible" 3rd edition. On page 279, here I quote:
"Command substitution creates what's called a
subshell
to run the
enclosed command. A subshell is a separate child shell generated from
the shell that's running the script. Because of that, any variables
you create in the script aren't available to the subshell command.Subshells are also created if you run a command from the command
prompt using the./
path, but they aren't created if you just run
the command without a path."
The last sentence confuses me. I tested with a simple script which exports some variables; the variables would not last after script exists however the script is invoked, from ./
path, or put the script in /usr/bin
and run it without a path. It seems to me that there is no difference how it invoked regarding to subshell.
What did I miss?
Best Answer
This is talking about constructions like:
In this example I am invoking two subshells using the two different supported notations for subshells. The first subshell runs the
date
command and the second subshell runs theuname
command. Theecho
command is executed by the original shell after both subshells have terminated.Here the author got it backwards. Variables created before invoking the subshell are available to the subshell. Variables created inside the subshell are only available to the subshell and will be gone once the subshell terminates.
It is very unclear what the author is trying to say here. If you invoke an external command the following will happen regardless of whether it is invoked with or without a path:
fork
s to create a new process.It is a new process, so any variables set by the external command will be unavailable to the parent process just like they would if it had been a subshell.
The author might have been referring to one of the following three scenarios:
#!
line at the start of the script.)read
, which syntactically looks like an external command found by searching thePATH
. But even though it syntactically looks the same, it will behave differently. Sinceread
will set a variable intended to be used by following commands,read
itself has to happen in the current process without anyfork
call. (Even internal commands that could safely be invoked as a subprocess are better done in the current process for performance reasons. Callingfork
is sort of expensive.). file
orsource file
. In this casefile
is not a script, but it is somewhat similar. All of the commands infile
will be invoked by the current shell without first callingfork
. (But of course the commands insidefile
could triggerfork
calls). In this case any#!
line infile
would be ignored, and any variables set byfile
would be available to your current shell.