Bash

管道 shell 腳本的標準錯誤並不總是顯示

  • February 18, 2013

我通過管道傳輸自己的 shell 腳本進行一些測試,並意外發現了一些奇怪的東西。也就是說,這些管道程序的標準錯誤並不總是顯示在螢幕上。

我簡化了腳本,這是我與 bash 的會話:

$ cat file1
echo stdout
echo stderr 1>&2
$ cat file2
echo stdout2
echo stderr2 1>&2
$ cat file3
echo stdout3
echo stderr3 1>&2

$ ./file1 | ./file2 | ./file3
stderr2
stderr
stdout3
stderr3

$ ./file1 | ./file2 | ./file3
stderr
stdout3
stderr3

$ ./file1 | ./file2 | ./file3
stderr2
stdout3
stderr3

我知道前兩個腳本的標準輸出失去了,因為 file3 沒有讀取任何內容,但這並不重要。

第 2 和第 3 種情況下的stderr2stderr輸出分別發生了什麼?

哦,比賽條件!為了產生這種效果,在幕後發生了一些事情。

首先,如果一個程序試圖寫入另一端已關閉的管道,該程序會收到一個SIGPIPE信號。預設情況下,這將結束該過程。你為什麼要這個?如果你執行cat my_huge_file | head -3,你只會看到文件的前三行,並且由於信號機制,cat知道在這三行之後停止。沒有它,它將讀取整個文件。

其次,管道中的所有程序都是並行執行的,哪個程序將首先完成是不可預測的。當一個程序結束時,它的所有文件描述符都被關閉——包括任何管道的讀取端。

所以發生的事情是,有時,例如,在寫入其標準輸出file3之前完全完成。file2然後,當file2確實嘗試寫入時,它會得到SIGPIPE,並在未到達echo stderr2行的情況下退出。但其他時候,在完成file2之前設法寫入標準輸出file3,在這種情況下它可以繼續。

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