文章出處

BASH_SUBSHELL 實現于 Bash 3.0,我一直想不到它在實際編碼中有什么用,后來在 Bash 的 Change Log 里找到一句話,才知道它是作調試用的:

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

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

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

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

$ (echo $BASH_SUBSHELL)

1

$ echo `echo $BASH_SUBSHELL`

1

$ echo $(echo $BASH_SUBSHELL)

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 中展開然后執行的。


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()