如何在bash shell中实现管道?

sky*_*net 2 unix linux bash shell

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

例如:我可以使用以下流程创建它吗?而不是让单个父进程有4个孩子,'grep z'可以是'grep y'的孩子而'grep y'是'grep x'的孩子,依此类推?

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

tha*_*guy 6

这取决于您的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                                                  
Run Code Online (Sandbox Code Playgroud)

但是,POSIX标准shell 需要在继续执行下一个命令之前等待最后一个阶段完成.由于进程只能等待子进程,这意味着最后一个进程必须是主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 $$,如果你不想学习execute_pipelineexecute_cmd.c的bash的源代码.

这样做的另一个好处是允许bash的PIPESTATUS数组和pipefail选项对管道中所有阶段的状态起作用,如果所有阶段都不是直接子进程,则无法获得这些阶段.

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

所以,是的,你可以使用任何你想要的配置,但在实践中(如在bash,dash,ashzsh),它会趋于平坦.