Recently I have been reading The Advanced Bash Script and I find something about the variable scope between parent and children shells puzzle me so much. Here it is:
Scene:
there are some ways to spawn a child shell:
first, (command-lists)
;
second, execute a non-built-in command or a script, and so on.
Since when we run a script in the parent script, the child script can not see the variables in the parent shell. Why is it possible that in the (command-lists)
struct the child shell can seen the variable in the parent shell.
e.g
(command-lists)
$ a=100
$ (echo $a)
100
$
run a script
$ cat b.sh
echo $a
$ a=100
$ ./b.sh
# empty
How?
In the case where you have a sub-shell run in the original script:
(command1; command2; ...)
the sub-shell is a direct copy of the original shell created by fork()
, and therefore has direct access to its own copy of all the original variables available to it.
Suppose the commands (command1
, command2
etc) in the sub-shell are themselves shell scripts. Those commands are executed by the sub-shell calling fork()
and then exec()
to create a new shell, and the new shell does not inherit the non-exported variables from the original shell.
Addressing your examples directly:
$ a=100
$ (echo $a)
100
$
Here, the sub-shell has its own copy of all the variables (specifically, a
) that the parent shell had access to. Any changes made in the sub-shell will not be reflected in the parent shell, of course, so:
$ a=100
$ (echo $a; a=200; echo $a)
100
200
$ echo $a
100
$
Now your second example:
$ cat b.sh
echo $a
$ a=100
$ ./b.sh
$ . ./b.sh
100
$ source ./b.sh
100
$ a=200 ./b.sh
200
$ echo $a
100
$ export a
$ ./b.sh
100
$
The variable a
is not exported, so the first time b.sh
is run, it has no value for $a
so it echoes an empty line. The second two examples are a 'cheat'; the shell reads the script b.sh
as if it was part of the current shell (no fork()
) so the variables are still accessible to b.sh
, hence it echoes 100 each time. (Dot or .
is the older mechanism for reading a script in the current shell; the Bourne shell in 7th Edition UNIX used it. The source
command is borrowed from the C shells as an equivalent mechanism.)
The command a=200 ./b.sh
exports a
for the duration of the command, so b.sh
sees and echoes the modified value 200
but the main shell has a
unchanged. Then when a
is exported, it is available to b.sh
automatically, hence it sees and echoes the last 100.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With