如何在Python 2.6中实现复杂的流程管道?

时间:2016-01-19 16:39:27

标签: python filter pipe subprocess yield

我喜欢将Python(2.6,对不起!)等效于这个shell管道:

$ longrunningprocess | sometextfilter | gzip -c

也就是说,我必须调用二进制longrunningprocess,通过sometextfilter过滤其输出,并需要输出gzip

我知道如何使用subprocess管道,但我需要管道输出(可能使用yield)而不是一次性完成。例如。这个 https://security.openstack.org/guidelines/dg_avoid-shell-true.html 仅适用于一次获取所有输出。

请注意,longrunningprocesssometextfilter都是外部程序,不能用Python函数替换。

提前感谢任何提示或示例!

2 个答案:

答案 0 :(得分:0)

同样,我认为这很困难,而Python(应该是)很容易。只是连接子进程才能正常工作,似乎:

def get_lines():
    lrp = subprocess.Popen(["longrunningprocess"],
                           stdout=subprocess.PIPE,
                           close_fds=True)
    stf = subprocess.Popen(["sometextfilter"],
                           stdin=lrp.stdout,
                           stdout=subprocess.PIPE,
                           bufsize=1,
                           close_fds=True)

    for l in iter(stf.stdout.readline, ''):
        yield l

    lrp.stdout.close()
    stf.stdout.close()
    stf.stdin.close()

    stf.wait()
    lrp.wait()

[J.F.Sebastian所做的修改。谢谢!]

然后我可以使用Pythons gzip进行压缩。

答案 1 :(得分:0)

shell语法针对单行进行了优化,使用它:

#!/usr/bin/env python2
import sys
from subprocess import Popen, PIPE

LINE_BUFFERED = 1
ON_POSIX = 'posix' in sys.builtin_module_names

p = Popen('longrunningprocess | sometextfilter', shell=True,
          stdout=PIPE, bufsize=LINE_BUFFERED, close_fds=ON_POSIX)
with p.stdout:
    for line in iter(p.stdout.readline, ''):
        print line,  # do something with the line
p.wait()

如果您想手动模拟管道:

#!/usr/bin/env python2
import sys
from subprocess import Popen, PIPE

LINE_BUFFERED = 1
ON_POSIX = 'posix' in sys.builtin_module_names

sometextfilter = Popen('sometextfilter', stdin=PIPE, stdout=PIPE,
                       bufsize=LINE_BUFFERED, close_fds=ON_POSIX)
longrunningprocess = Popen('longrunningprocess', stdout=sometextfilter.stdin, 
                           close_fds=ON_POSIX)
with sometextfilter.stdin, sometextfilter.stdout as pipe:
    for line in iter(pipe.readline, ''):
        print line, # do something with the line
sometextfilter.wait()
longrunningprocess.wait()