Bash
子程序是否保持管道打開?
我試圖了解在管道中執行時啟動子程序的程序的行為。
這個 bash 程序 fork.sh 立即列印並返回:
(sleep 1) & echo 'here'
但是當連接到管道時,讀取端似乎在等待睡眠完成。
$ time bash fork.sh | wc 1 1 5 real 0m1.014s
我也在 Ruby 中嘗試過這個,通過一些額外的呼叫來防止睡眠阻塞:
Process.detach(fork { sleep 1 }) puts 'here'
fork { sleep 1 Process.daemon } puts 'here'
但它們的行為相同。
我想知道是什麼原因造成的(在 Unix、文件描述符等方面),以及是否有辦法重寫其中任何一個,以便管道在一秒鐘內返回。
編輯:下面的答案幫助我注意到了 Ruby 範例的問題:
daemon()
必須先呼叫。我曾以為它以某種方式應用於整個過程。
- 子程序從其父程序繼承所有文件描述符。
- 執行命令時(就像你的
sleep
這裡假設你的 shell 沒有內置它),只有標有close-on-exec標誌的文件描述符被關閉,但 shell 永遠不會在標準輸出(fd 1)上設置該標誌。- 只有當所有指向其寫入端的文件描述符都已關閉時,管道閱讀器才會獲得 EOF 。
time bash fork.sh | wc
你應該讓你的
sleep
程序(從 開始fork.sh
)放棄它的標準輸出,它指向管道的寫入端正在wc
讀取;在fork.sh
:(sleep 1 >/dev/null) & echo 'here'
在這種情況下
sleep .. >&-
(關閉標準輸出,而不將其重定向到其他地方)也可以工作,但我一般不建議這樣做,因為如果程序隨後打開某個文件,返回的文件描述符將為 1 = stdout,這可能會中斷假設和触發錯誤。