我运行命令时不是创建了一个子shell吗bash
?例如,执行后bash
,我无法访问非导出变量的值。那么,我使用bash命令切换到的环境不是当前bash shell下运行的子shell吗?
:~$ value="testing"
:~$ echo $value
testing
:~$ bash
:~$ ps f
PID TTY STAT TIME COMMAND
82 tty1 S 0:00 -bash
97 tty1 S 0:00 \_ bash
124 tty1 R 0:00 \_ ps f
:~$
:~$ echo $value
:~$ exit
exit
:~$ export value
:~$ bash
:~$ echo $value
testing
:~$
答案1
不,这不是一个子外壳。 bash 中的子 shell 使用该变量进行标记BASH_SUBSHELL
。对于每个级别的子 shell,该值都会增加 1:
$ echo $BASH_SUBSHELL
0
$ ( echo $BASH_SUBSHELL )
1
$ ( ( echo $BASH_SUBSHELL ) )
2
$ ( ( ( echo $BASH_SUBSHELL ) ) )
3
$ ( ( ( ( echo $BASH_SUBSHELL ) ) ) )
4
$ ( ( ( ( ( echo $BASH_SUBSHELL ) ) ) ) )
5
但是,如果您只是启动另一个 shell,则此变量不会更改:
$ echo $BASH_SUBSHELL
0
$ bash
$ echo $BASH_SUBSHELL
0
这是因为当您运行新的 bash shell 时,这是一个全新的实例。是的,导出的变量将被继承,因为这是一个孩子原始 bash 实例的 shell,但正如您在上面看到的,它实际上并不是它的子 shell。请注意,子 shell 继承所有变量,而不仅仅是导出的变量:
$ foo=var
$ ( echo $BASH_SUBSHELL; echo $foo )
1
var
$ bash
$ echo $var ## <-- prints an empty line
这也在(强调我的)COMMAND EXECUTION ENVIRONMENT
中进行了解释:man bash
命令替换、用括号分组的命令以及在子 shell 环境中调用异步命令这是 shell 环境的副本,除了 shell 捕获的陷阱会重置为 shell 在调用时从其父级继承的值。作为管道一部分调用的内置命令也在子 shell 环境中执行。对子 shell 环境所做的更改不会影响 shell 的执行环境。
因此,子 shell 环境几乎是其父 shell 的完全相同的副本,其中包括所有变量,而不仅仅是导出的变量。
答案2
命令执行环境部分bash手册:
当要执行除内置函数或 shell 函数之外的简单命令时,将在由以下内容组成的单独执行环境中调用它。除非另有说明,这些值都是从 shell 继承的。
- shell 变量和函数标记为出口,以及为命令导出的变量,在环境中传递
因此:
bash
不是内置函数或 shell 函数,而是在子 shell 中执行。它从其父 shell 继承标记为导出的变量。
正如您的实验所示,只有在
value
导出时bash
,子 shell 才会获取它。
这并不意味着bash
您获得的 shell 是子 shell,而是说它是从子 shell 执行的,替换了它,因此涉及的子 shell 是短暂的,只是一个中间人。
参见下图。
图表用直径
您键入bash
,这将分叉当前 shell,创建一个相同的 shell。黄色的兄弟姐妹等待橙色的兄弟exec
姐妹bash
。任何非内置命令(zsh
、g++
、firefox
...)都会发生这种情况,而不仅仅是bash
.所有环境变量都是继承的,但由于value
不是其中之一并且没有导出,因此蓝色 Bash 不会接收它。
资料来源: