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」了。