BASH_SUBSHELL 變量不生效的狀況

BASH_SUBSHELL 實現於 Bash 3.0,我一直想不到它在實際編碼中有什麼用,後來在 Bash 的 Change Log 裏找到一句話,才知道它是做調試用的:html

New variables to support the bash debugger: BASH_ARGC, BASH_ARGV,
BASH_SOURCE, BASH_LINENO, BASH_SUBSHELL, BASH_EXECUTION_STRING,
BASH_COMMANDshell

BASH_SUBSHELL 是 subshell 嵌套層次的累加器,那麼按理說,全部的 subshell 裏這個變量都應該加 1。那 Bash 的哪些語法是在 subshell 裏執行的呢?下面列舉一下:bash

  1. 小括號分組 (...)
  2. 命令替換 `...` 和 $(...)
  3. 進程替換 <() 和 >()
  4. 管道 ... | ...
  5. 後臺命令 ... &

那麼當 BASH_SUBSHELL 出如今這些語法中時,它的值就應該加 1,對不對?然而實際狀況卻不是這樣的,在我寫這篇文章時,Bash 的最新穩定版是 4.3.30,在該版本中,BASH_SUBSHELL 只會在上面列出的 1 和 2 兩種語法裏生效:編碼

$ (echo $BASH_SUBSHELL)debug

1調試

$ echo `echo $BASH_SUBSHELL`htm

1進程

$ echo $(echo $BASH_SUBSHELL)get

1編譯

在後三種語法裏不生效: 

$ cat <(echo $BASH_SUBSHELL)

0

$ echo $BASH_SUBSHELL | cat

0

$ echo $BASH_SUBSHELL &

[1] 91155

$ 0

搜索了一翻,在 help-bash 上發現已經有人提了個 bug,不過他僅僅提到了進程替換和命令替換中 BASH_SUBSHELL 表現不一致的事,Bash 做者也回覆說會在 Bash 下個版本也就是是 4.4 裏修復。而後我下了 4.4 alpha 版編譯以後發現,進程替換中 BASH_SUBSHELL 是生效了,但在管道和後臺命令中仍沒效果,因而我又頂起了這個郵件,詢問 Bash 做者是否能一塊兒修復,他的回覆是,後臺命令那個他會修的,但管道命令那個不許備修復。而後我就沒再追問爲何了,應該是實現上有困難,畢竟這是 Bash 私有的東西,做者有權決定該不應修。總之,我想說的是,在將來 Bash 4.4 發佈的時候,BASH_SUBSHELL 在除了管道以外的其餘子 Shell 裏,都應該能生效了。

此外,當我問這個問題的時候,有人回覆說,之因此 BASH_SUBSHELL 爲 0,是由於它是在父 Shell 裏展開以後才傳入子 Shell 的,也就是說,echo $BASH_SUBSHELL | cat 在傳入子 Shell 的時候就已經成了 echo 0 | cat,但這是不對的,咱們能夠舉一個反例,若是真是那樣的話,echo $BASHPID | cat 應該和 echo $BASHPID 的輸出同樣,但實際倒是不同的。因此能夠總結一下就是,歷來都不存在「在父 Shell 中展開變量,在子 Shell 裏執行展開後的命令」 這一回事,全部的變量都是在子 Shell 中展開而後執行的。

相關文章
相關標籤/搜索