2015-07-20 100 views
2

我正在嘗試爲shell執行管道實現。我已經以下面的方式實施,它的工作原理。例如:如果我想要做,ls | grep x | grep y | grep z,我從父進程創建4個子進程並與它們一起工作。還有其他方法嗎?在bash shell中如何實現管道?

例如:我可以使用以下流程創建它嗎?可以'grep z'成爲'grep y'的孩子並且'grep y'成爲'grep x'的孩子等等,而不是讓4個孩子成爲單個父進程?

我很好奇管道功能是如何在bash shell中實現的。我嘗試下載源代碼並理解它,但是丟失了。

回答

5

這取決於你的shell和你調用的程序。

從理論上講,你可以使用具有N個非根節點的任何可變參數樹的可能性,其中一些組合爆炸:

shell    shell     shell       
    /    / \    / \       
    grep x    ls  grep y  ls grep y      
/\    \   \    / \      
ls grep y   grep x grep z  grep x grep z     
     \                  
     grep z             

一個POSIX標準的shell,雖然是required to wait for the last stage to finish與繼續之前下一個命令。由於進程只能在子進程中使用wait,這意味着最後一個階段必須是主shell的子進程。 POSIX補貼額外等待所有階段,這是bash和大多數其他shell所做的(嘗試sleep 5 | true)。

這意味着bash將所有進程作爲自己的子進程啓動,您可以使用例如strace -f -e clone bash -c 'sleep 5 | sleep 5 | sleep 5'sleep 5 | sleep 5 | sleep 5 & pstree -p $$,如果您不想在bash源代碼中的execute_cmd.c中研究execute_pipeline

這還有一個額外的好處,就是允許bash的PIPESTATUS數組和pipefail選項作用於管道中所有階段的狀態,如果所有階段都不是直接的子進程,那麼這是不可能的。

另一個考慮是程序很少處理他們沒有想到的孩子。充其量,你將得到一個殭屍進程,最壞的情況是它會干擾進程的正確性。這意味着ls不應該是grep的直接子代,反之亦然。但是,您可以通過double fork將其設置爲孫子,以便init可以對此負責。

所以,是的,你可以使用任何你想要的配置,但在實踐中(如在bashdashashzsh),它會趨於平坦。

+0

哇。非常感謝,這正是我正在尋找的。我需要一段時間來處理你給我的所有信息,並嘗試理解事情。謝謝 :) – skynet