当我运行“bash”命令时,不是创建了一个子shell吗?

当我运行“bash”命令时,不是创建了一个子shell吗?

我运行命令时不是创建了一个子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。任何非内置命令(zshg++firefox...)都会发生这种情况,而不仅仅是bash.所有环境变量都是继承的,但由于value不是其中之一并且没有导出,因此蓝色 Bash 不会接收它。

资料来源:

相关内容