Bash

從標準輸入讀取在 bash 和 zsh 中的工作方式不同

  • October 21, 2018

我正在嘗試將命令的輸出通過管道傳輸到read我的 shell 的內置函式中,並且我得到了不同的行為zshand bash

$ bash -c 'echo hello | read test; echo $test'

$ zsh -c 'echo hello | read test; echo $test'
hello

雖然這在 中不起作用bash,但以下適用於兩者:

$ bash -c 'echo hello | while read test; do echo $test; done'
hello
$ zsh -c 'echo hello | while read test; do echo $test; done'
hello

這是為什麼?我用read錯了嗎?test="$(echo hello)"與迫使我更仔細地處理引用問題相比,我發現在腳本中使用它更具可讀性。

您正在觀察未使用 POSIX 標準化的結果。

POSIX 沒有標準化解釋器如何執行管道。

對於歷史悠久的 Bourne Shell,管道中最右邊的程序甚至不是主 shell 的子程序。這樣做的原因是因為這個實現很慢但需要很少的程式碼——如果你只有 64 kB 的記憶體,這很重要。由於在此變體中,read命令在子程序中執行,因此在子程序中分配 shell 變數在主 shell 中不可見。

kshor bosh(最近的 Bourne Shell)這樣的現代 shell 創建管道的方式是,管道中的所有程序都是主 shell 的直接子程序,如果最右邊的程序是內置 shell,它甚至由主 shell 執行。

這一切都需要讓read程序修改主 shell 的 shell 變數。所以只有在這個變體中(BTW 是最快的變體)才允許主 shell 看到變數賦值的結果。

在您的第二個範例中,整個while循環在同一個子程序中執行,因此允許列印 shell 變數的修改版本。

目前有一個請求添加對 POSIX shell 的支持,以獲取有關任何管道命令是否具有非零退出程式碼的資訊。為了實現這一點,shell 必須以管道中的所有程序都是主 shell 的直接子級的方式實現。這接近允許

echo foo | read val; echo $val

做預期的事情,因為那時只缺少在主 shell 中執行讀取的要求。

引用自:https://unix.stackexchange.com/questions/476834