如何在Shell程序中处理多重管道?

问题描述

我正在使用os库在python中制作外壳程序,并且希望实现多个管道功能,但是由于无法确定如何处理STDOUT和孩子以及父母,我陷入了困境。

我想我必须继续将结果写入stdout并在有更多管道的情况下将其复制。

因此,如果我有此命令,我应该只获得找到var的行:

ls -l / | grep v | grep var

然后,我使外壳将命令分为字符串列表:

command = [['ls','-l','/'],['grep','root'],'var']]

然后,我需要在新的孩子中派生并复制前两个的输出,并将输出传递到最后一个

我对如何使用1个以上的管道执行此操作感到非常困惑,甚至对如何动态执行此操作感到困惑。

我现在坐在那里,尝试以不同的方式向程序中静态添加第二个管道,但是我对如何动态地向程序中添加 n 个管道有一些想法通过使用迭代或递归。

我做一个管道的工作代码如下:

from os import (
    execvp,wait,fork,pipe,dup2,_exit,close,)

STDIN   = 0
STDOUT  = 1
CHILD   = 0


def command(cmd):
    try:
        execvp(cmd[0].strip(),cmd)
    except OSError as e:
        print(e)

def piping(cmd):
    reading,writing = pipe()
    pid = fork()
    if pid > CHILD:
        wait()
        close(writing)
        dup2(reading,STDIN)
        command(cmd[1])
    elif pid == CHILD:
        close(reading)
        dup2(writing,STDOUT)
        command(cmd[0])
        _exit(0)

def main():
    pid = fork()
    if pid > CHILD:
        wait()
    if pid == CHILD:
        piping([['ls','-al','v'],'var']])
        _exit(0)

main()

因此,要想使用3个管道,我想我可以做这样的事情。但这不起作用。

我只是更改了pipeline()函数以在孩子内部获得一个额外的fork,并使用dup2方法交换新旧管道中通道的输入/输出


def piping(cmd):
    print(cmd)
    r1,w1 = pipe()
    pid = fork()
    if pid > CHILD:
        wait()
        close(w1)
        dup2(r1,STDIN)
        command(cmd[2])
    elif pid == CHILD:
        r2,w2 = pipe()
        pid2 = fork()
        if pid2 > CHILD:
            wait()
            close(w2)
            close(r1)
            dup2(w1,r2)
            command(cmd[1])
        elif pid2 == CHILD:
            close(r2)
            dup2(w2,STDOUT)
            command(cmd[0])
            _exit(0)

请帮助我,我真的很想学习如何做!谢谢:-)

解决方法

我知道了!

我只需要创建一个函数 child()即可负责创建新管道和新派生。然后仅写入父级的那个通道。

所以我将 piping()函数更改为此。

def piping(cmd):
    reading,writing = pipe()
    pid = fork()
    if pid > CHILD:
        wait()
        close(writing)
        dup2(reading,STDIN)
        command(cmd[len(cmd)-1])
    elif pid == CHILD:
        child(cmd[:-1],reading,writing)

然后我创建了 child()函数:

def child(cmd,r1,w1):
    r2,w2 = pipe()
    pid2 = fork()
    if pid2 > CHILD:
        wait()
        close(w2)
        close(r1)
        dup2(r2,STDIN)
        dup2(w1,STDOUT)
        command(cmd[len(cmd)-1])
    elif pid2 == CHILD:
        if len(cmd) > 2:
            child(cmd[:-1],r2,w2)
        else:
            close(r2)
            dup2(w2,STDOUT)
            command(cmd[0])
            _exit(0)

然后我就可以将无数个管道传递给shell并获得结果! :D