当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何使用subprocess.Popen通过管道连接多个进程?》经验,为你挑选了3个好方法。

如何使用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是对的,最好避免首先解决这个问题!



1> 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 data\n" )

将部分工作委托给shell.让它用管道连接两个进程.

你可以更快乐地将'script.awk'改写成Python,消除awk和管道.

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

[有太多理由通过评论回复.]

    Awk正在增加一个没有重大价值的步骤.关于awk的处理没有什么独特之处,Python无法处理.

    对于大型数据集,从awk到sort的流水线操作可以改善经过的处理时间.对于短数据集,它没有显着的好处.快速测量awk >file ; sort fileawk | sort显示并发性有助于.使用sort,它很少有用,因为sort不是一次性过滤器.

    "Python to sort"处理的简单性(而不是"Python to awk to sort")可以防止这里提出的确切类型的问题.

    Python - 虽然比awk更啰嗦 - 也是明确的,其中awk具有某些隐含的规则,这些规则对新手不透明,并且对非专业人员造成混淆.

    awk(就像shell脚本本身一样)添加了另一种编程语言.如果所有这些都可以用一种语言(Python)完成,那么取消shell和awk编程就会消除两种编程语言,允许某人专注于任务的价值生成部分.

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

侧边栏为什么构建管道(a | b)非常困难.

当shell遇到a | b它时,必须执行以下操作.

    fork原始shell的子进程.这最终将成为b.

    构建一个os管道.(不是Python subprocess.PIPE)但调用os.pipe()返回两个通过公共缓冲区连接的新文件描述符.此时,进程具有来自其父级的stdin,stdout,stderr,以及将是"a的stdout"和"b的stdin"的文件.

    叉一个孩子.孩子用新的标准替换它的标准输出.执行该a过程.

    b子关闭用新b的标准输入替换其标准输入.执行该b过程.

    b孩子等待a完成.

    父母正在等待b完成.

我认为上面的内容可以递归地用于生成a | b | c,但是你必须隐式地将长管道括起来,将它们视为它们a | (b | c).

因为Python有os.pipe(),os.exec()并且os.fork()你可以替换,sys.stdin并且sys.stdout有一种方法可以在纯Python中执行上述操作.实际上,您可以使用os.pipe()和编写一些快捷方式subprocess.Popen.

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


"代码更短"并不 - 实际上 - 意味着更简单.它只意味着更短.Awk有很多假设和隐藏的功能,使代码很难使用.Python虽然更长,却是明确的.
我认为Awk实际上非常适合我正在做的事情,代码比等效的Python代码更短更简单(毕竟它是一种领域特定的语言.)
`-c`已包含在`shell = True`中.

2> 小智..:
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)


这个答案不是更加pythonic更好吗?在子进程文档中不鼓励使用`shell = True`.我看不出人们上调@ S.Lott回答的原因.
@KenT:Shell解决方案更具可读性,并且不易出错(如果您不接受不受信任的输入)。pythonic解决方案将[使用`plumbum`(Python中嵌入的shell语法)](http://stackoverflow.com/a/16709666/4279)或另一个接受类似语法(以字符串形式)并构造管道的模块为您服务(与本地`/ bin / sh`相同)。
@SamWatkins:你的代码中不需要`p1.wait()`.`p1.communicate()`收获子进程.

3> jfs..:

要模拟shell管道:

from subprocess import check_call

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

不调用shell(参见17.1.4.2.替换shell管道):

#!/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")()

推荐阅读
mobiledu2402851377
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有