【问题标题】:How to deal with mutliple pipes in shell program?如何处理shell程序中的多个管道?
【发布时间】:2020-09-18 12:35:21
【问题描述】:

我正在使用 os 库在 python 中制作一个 shell,我想制作多个管道功能,但我遇到了困难,因为我不确定如何处理 STDOUT 以及孩子和父母。

我想我必须继续将结果写入标准输出并复制它以防更多管道。

所以如果我有这个命令,我应该只得到找到 var 的那一行:

ls -l / | grep v | grep var

然后我让 shell 将命令分成一个字符串列表:

command = [['ls', '-l', '/'], ['grep', 'root'], ['grep', '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','/'],['grep','v'],['grep','var']])
        _exit(0)

main()

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

我只是更改了 pipe() 函数以在 child 内部获得一个额外的 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)

请帮帮我,我真的很想学习如何做到这一点!谢谢:-)

【问题讨论】:

  • re:“我想我必须继续将结果写入标准输出并复制它以防更多管道。”您不希望您的 shell 读取它生成的子节点的任何输出。在管道a | b | c 中,shell 仅运行b,其标准输入位于a 的标准输出的管道另一端。如果您的 shell 正在读取 a 的输出并将其写入 b,那么您做错了。
  • 我正在写一个 |和阅读| b 但我想如果我有 3 个管道:那么我必须写一个 |写 |乙 |并阅读 | c,所以这阻止我在孩子内部调用相同的函数,因为我总是写一个 |和阅读|乙。
  • 也许我必须创建一个可以返回相关管道通道的函数。
  • 我想我现在明白了!!!! :D :D

标签: python pipe fork python-os


【解决方案1】:

我想通了!!

我只需要创建一个函数 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

【讨论】:

    猜你喜欢
    • 2019-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多