如何使用subprocess.Popen通过管道连接多个进程?

如何使用Python subprocess模块执行以下shell命令?

echo "input data" | awk -f script.awk | sort > outfile.txt

输入数据将来自一个字符串,所以我实际上并不需要echo 。 我有这么远,任何人都可以解释我如何通过sort这个问题吗?

p_awk = subprocess.Popen(["awk","-f","script.awk"],
                          stdin=subprocess.PIPE,
                          stdout=file("outfile.txt", "w"))
p_awk.communicate( "input data" )

更新 :请注意,虽然下面接受的答案实际上并没有回答问题的问题,但我相信S.Lott是正确的,最好避免必须首先解决这个问题!


你会对以下事情感到高兴。

import subprocess

awk_sort = subprocess.Popen( "awk -f script.awk | sort > outfile.txt",
    stdin=subprocess.PIPE, shell=True )
awk_sort.communicate( b"input datan" )

将部分工作委托给shell。 让它用流水线连接两个进程。

如果将'script.awk'重写为Python,你会感到很开心,从而消除awk和管道。

编辑 。 提出awk没有帮助的一些原因。

[通过评论回复的原因太多了。]

  • Awk正在增加一个没有重要价值的步骤。 关于awk的处理没有什么独特的,Python不处理。

  • 对awk进行流水线排序以处理大量数据可能会缩短处理时间。 对于短的数据集,它没有显着的好处。 快速测量awk >file ; sort file awk >file ; sort fileawk | sort awk | sort会揭示并发的帮助。 排序,它很少帮助,因为排序不是一次性过滤器。

  • “Python排序”处理的简单性(而不是“Python来排序”)可以防止在这里提出的确切类型的问题。

  • Python - 虽然比awk更热门 - 但它也是明确的,其中awk具有对新手不透明的某些隐含规则,并且会让非专业人员感到困惑。

  • awk(如shell脚本本身)增加了另一种编程语言。 如果所有这些都可以用一种语言来完成(Python),那么消除shell和awk编程就可以消除两种编程语言,从而使人们可以专注于任务的产生价值的部分。

  • 底线:awk无法增加显着的价值。 在这种情况下,awk是一个净成本; 它增加了足够的复杂性,有必要提出这个问题。 删除awk将是一个净收益。

    边栏为什么建立管道( a | b )太难了。

    当shell遇到a | b a | b必须做到以下几点。

  • 分叉原壳的子过程。 这最终会变成b。

  • 建立一个os管道。 (不是Python子os.pipe() ,而是调用os.pipe() ,它返回两个通过公共缓冲区连接的新文件描述符。 在这一点上,该进程的父级标准输出stdout,标准错误stderr,以及一个将成为“a标准输出”和“b标准输入”的文件。

  • 叉一个孩子。 孩子用新的stdout替换它的stdout。 执行a过程。

  • b关闭的孩子用新的b的stdin替换它的stdin。 执行b过程。

  • b孩子等待完成。

  • 父母正在等待b完成。

  • 我认为上述可以递归地用于产生a | b | c a | b | c a | b | c ,但是你必须隐式地加长长管道,把它们看作是a | (b | c) a | (b | c)

    由于Python有os.pipe()os.exec()os.fork() ,你可以替换sys.stdinsys.stdout ,所以有一种方法可以在纯Python中完成上述操作。 事实上,你可以制定出使用一些快捷键os.pipe()subprocess.Popen

    但是,将该操作委托给shell更容易。


    import subprocess
    
    some_string = b'input_data'
    
    sort_out = open('outfile.txt', 'wb', 0)
    sort_in = subprocess.Popen('sort', stdin=subprocess.PIPE, stdout=sort_out).stdin
    subprocess.Popen(['awk', '-f', 'script.awk'], stdout=sort_in, 
                     stdin=subprocess.PIPE).communicate(some_string)
    

    模拟shell管道:

    from subprocess import check_call
    
    check_call('echo "input data" | a | b > outfile.txt', shell=True)
    

    而无需调用外壳(请参阅17.1.4.2。替换外壳管道):

    #!/usr/bin/env python
    from subprocess import Popen, PIPE
    
    a = Popen(["a"], stdin=PIPE, stdout=PIPE)
    with a.stdin:
        with a.stdout, open("outfile.txt", "wb") as outfile:
            b = Popen(["b"], stdin=a.stdout, stdout=outfile)
        a.stdin.write(b"input data")
    statuses = [a.wait(), b.wait()] # both a.stdin/stdout are closed already
    

    plumbum提供了一些语法糖:

    #!/usr/bin/env python
    from plumbum.cmd import a, b # magic
    
    (a << "input data" | b > "outfile.txt")()
    

    类比:

    #!/bin/sh
    echo "input data" | awk -f script.awk | sort > outfile.txt
    

    是:

    #!/usr/bin/env python
    from plumbum.cmd import awk, sort
    
    (awk["-f", "script.awk"] << "input data" | sort > "outfile.txt")()
    
    链接地址: http://www.djcxy.com/p/13471.html

    上一篇: How do I use subprocess.Popen to connect multiple processes by pipes?

    下一篇: Complex Regex that can filter word