Bash

子程序是否保持管道打開?

  • November 13, 2019

我試圖了解在管道中執行時啟動子程序的程序的行為。

這個 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()必須先呼叫。我曾以為它以某種方式應用於整個過程。

  1. 子程序從其父程序繼承所有文件描述符。
  2. 執行命令時(就像你的sleep這裡假設你的 shell 沒有內置它),只有標有close-on-exec標誌的文件描述符被關閉,但 shell 永遠不會在標準輸出(fd 1)上設置該標誌。
  3. 只有當所有指向其寫入端的文件描述符都已關閉時,管道閱讀器才會獲得 EOF 。
time bash fork.sh | wc

你應該讓你的sleep程序(從 開始fork.sh)放棄它的標準輸出,它指向管道的寫入端正在wc讀取;在fork.sh

(sleep 1 >/dev/null) &
echo 'here'

在這種情況下sleep .. >&-(關閉標準輸出,而不將其重定向到其他地方)也可以工作,但我一般不建議這樣做,因為如果程序隨後打開某個文件,返回的文件描述符將為 1 = stdout,這可能會中斷假設和触發錯誤。

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