SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,而 BASH_SUBSHELL 是记录一个 Bash 进程实例中多个子 Shell(subshell)嵌套深度的累加器。html
看不懂上面这句话没关系,由于是我临时编的。其实若是你混淆了这两个变量,我猜你多半是对 BASH_SUBSHELL 这个变量名中的 subshell 概念不清,下面咱们就讲讲什么是 subshell,什么不是。shell
不少人误觉得在 Bash 里面再执行一次 Bash,或者再执行一个 Shell 脚本就是进入子 Shell 了,因此他们会有下面这样的疑问:bash
$ bash # 执行另一个 bash 命令app $ echo $BASH_SUBSHELL ide $ 0 # 怎么仍是 0,我这不是在上个 Shell 的子 Shell 里吗?函数 $ echo ' echo $BASH_SUBSHELL ' > test; chmod +x test; ./test;ui $ 0 # 难道再执行 Shell 脚本也不是子 Shell?spa |
然而并非,这些都不是子 Shell,这种状况只能描述成是“当前 Shell 启动了个外部命令,而这个外部命令恰好是个 Shell”,真正的子 Shell 是不须要从新执行硬盘上的外部命令的,所有是内存中的操做。上面这个示例中的 BASH_SUBSHELL 都应该替换成 SHLVL 才能看到累加效果。翻译
有几本书给子 Shell 下过定义:htm
Advanced Bash-Scripting Guide 说:
A subshell is a child process launched by a shell (or shell script).
A subshell is a forked copy of the parent shell and shares it’s environment.
The Korn Shell: Unix & Linux Programming Manual 说:
A subshell is a separate copy of the parent shell, so variables, functions, and aliases from the parent shell are available to the subshell
第一本书流传较广,但它这句话说的太泛了,很容易误导人,虽然子 Shell 的确是当前 Shell 的子进程,但当前 Shell 的子进程不必定都是子 Shell(可能已经替换成了其余程序)。在 Bash 里面,只有特定的语法才会让代码进入子 Shell,好比管道两边的命令,好比用小括号括起来等等:
$ (echo $BASH_SUBSHELL) 1 $ ( ( ( ( (echo $BASH_SUBSHELL) ) ) ) ) 5 |
真正的子 Shell 能够访问其父 Shell 的任何变量,而经过再执行一次 bash 命令所启动的 Shell 只能访问其父 Shell 传来的环境变量。这篇教程里面专门写了个例子:
For an example of the difference between a subshell and a child process that happens to be a shell:
unset a; a=1 (echo "a is $a in the subshell") sh -c 'echo "a is $a in the child shell"'
In the subshell, the regular shell variable a is visible; but because it is not exported, the full child process does not see it.
上面的例子中把当前 Shell 执行外部命令 sh 启动的 Shell 叫作 child shell,惋惜在中文里仍是得翻译成子 Shell。。。
从 c 语言层面讲,真正的子 Shell 是当前 Shell 进程调用了 fork() 函数,在内存中复制出一个几乎如出一辙的子进程。而执行 bash 命令启动的所谓 child shell 是在执行 fork() 函数的基础上,又执行了一次 execve() 函数,execve() 函数会从新加载硬盘上的 bash 命令并执行,替换刚才 fork 出来的那个 shell 进程,除了传入的环境变量外,是个崭新的进程。
总结一下就是说,SHLVL 变量是记录了所谓的 child shell 的嵌套深度,而 BASH_SUBSHELL 是记录了 subshell 的嵌套深度。
把 child shell 叫成子 Shell,在口头上说说还能够,由于中文里没有其它什么好的叫法用来指代它,但你内心得明白,这不是术语子 Shell 真正的含义。
写到这里,我想这篇文章的标题应该改为“什么是子 Shell”了。