如何在bash shell中实现管道?

时间:2015-07-20 22:00:33

标签: linux bash shell unix

我正在尝试为shell执行管道实现。我已经按照以下方式实现了它的工作原理。例如:如果我想这样做,ls | grep x | grep y | grep z,我正在从父进程创建4个子进程并使用它们。有没有其他方法可以做到这一点?

例如:我可以使用以下流程创建它吗?而不是让单个父母过程有4个孩子,而不是'grep z'成为' grep y'并且' grep y'成为' grep x'的孩子等等 ?

我很好奇如何在bash shell中实现管道功能。我尝试下载源代码并理解它但丢失了。

1 个答案:

答案 0 :(得分: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_pipeline中学习execute_cmd.c

这样做的另一个好处是允许bash的PIPESTATUS数组和pipefail选项对管道中所有阶段的状态起作用,如果所有阶段都不是直接的话,你就无法获得儿童过程。

另一个考虑因素是程序很少处理他们没有预料到的孩子。充其量,你会得到一个僵尸进程,最坏的情况是它会干扰进程的正确性。这意味着ls永远不应该是grep的直接孩子,反之亦然。但是,您可以通过double fork将其设为孙子,以便init可以对此负责。

所以是的,您可以使用您想要的任何配置,但在实践中(例如bashdashashzsh),它可以使用往往是扁平的。