2015-10-15 182 views
1

看看下面的代碼:擊重定向:命名管道和EOF

rm -f pipe 
mkfifo pipe 

foo() { 
    echo 1 
    sleep 1 
    echo 2 
} 

#1 
exec 3< <(foo &) 
cat <&3 # works 

#2 
foo >pipe & 
cat <pipe # works 

#3 
exec 3<>pipe 
foo >&3 & 
cat <&3 # hangs 

#4 -- update: this is the correct approach for what I want to do 
foo >pipe & 
exec 3<pipe 
rm pipe 
cat <&3 # works 

爲什麼做法#3掛起,而有的則沒有?有沒有辦法讓方法#3不掛?

理由:我希望用準命名管道連接多個異步運行子過程,爲了這個,我需要做一個文件描述符指向它後刪除管:在方法3

mkfifo pipe 
exec {fd}<>pipe 
rm pipe 
# use &$fd only 

回答

2

問題是FIFO pipe然後有2個寫入器:bash腳本(因爲您已使用exec 3<>打開了它的讀取/寫入)和運行foo的子shell。當所有編寫者關閉文件描述符時,您將閱讀EOF。一個作者(運行foo的子shell)將很快(大約1秒後)退出,因此關閉文件描述符。然而,另一個作者(主外殼)僅在它退出時關閉文件描述符,因爲在任何地方都沒有關閉文件描述符3。但它不能退出,因爲它等待cat先退出。這是一個僵局:

  • cat等待一個EOF
  • 的EOF只有當主殼關閉
  • 主殼等待cat的FD(或出口)終止
出現

因此,你永遠不會退出。

情況2的工作原理是因爲管道只有一個寫入器(運行foo的子shell)很快退出,因此將讀取EOF。在情況1中,也只有一個作者,因爲你打開fd 3只讀(exec 3<)。

編輯:刪除關於案例4的無稽之談不正確(見評論)。這是正確的,因爲作者無法在閱讀器連接之前退出,因爲在閱讀器尚未打開時打開文件時它也會被阻止。 不幸的是,新添加的案例4不正確。它很活潑,只有在exec 3<pipe運行前foo沒有終止(或關閉管道)時才起作用。

同時檢查fifo(7)手冊頁:

內核維護只有一個管道對象由至少一個進程打開的每個FIFO特殊文件。在數據通過之前,FIFO必須在兩端打開(讀和寫)。通常,打開FIFO模塊直到另一端也打開。

+0

釘住它。 'exec 3 <>'使得主外殼成爲編寫器,這導致了EOF問題。 – Irfy

+0

@Iffy我補充說。在情況1中,文件描述符3在主外殼中以只讀方式打開。因此,管道永遠不會有超過1個作者。 –

+0

在此幫助下,我重寫了刪除管道的代碼,以便按預期工作,謝謝。 – Irfy