Bash
管道 shell 腳本的標準錯誤並不總是顯示
我通過管道傳輸自己的 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 種情況下的
stderr2
和stderr
輸出分別發生了什麼?
哦,比賽條件!為了產生這種效果,在幕後發生了一些事情。
首先,如果一個程序試圖寫入另一端已關閉的管道,該程序會收到一個
SIGPIPE
信號。預設情況下,這將結束該過程。你為什麼要這個?如果你執行cat my_huge_file | head -3
,你只會看到文件的前三行,並且由於信號機制,cat
知道在這三行之後停止。沒有它,它將讀取整個文件。其次,管道中的所有程序都是並行執行的,哪個程序將首先完成是不可預測的。當一個程序結束時,它的所有文件描述符都被關閉——包括任何管道的讀取端。
所以發生的事情是,有時,例如,在寫入其標準輸出
file3
之前完全完成。file2
然後,當file2
確實嘗試寫入時,它會得到SIGPIPE
,並在未到達echo stderr2
行的情況下退出。但其他時候,在完成file2
之前設法寫入標準輸出file3
,在這種情況下它可以繼續。