如何在管道上使用`subprocess`命令


Answers:


438

要将管道与subprocess模块一起使用,必须通过shell=True

但是,出于种种原因,这并不是真正可取的选择,其中不仅包括安全性。相反,请分别创建psgrep流程,并将输出从一个管道传递到另一个管道,如下所示:

ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()

但是,在您的特定情况下,简单的解决方案是先调用subprocess.check_output(('ps', '-A'))然后str.find在输出上。


81
+1用于分隔输出/输入以避免使用shell=True
Nicolas

5
不要忘记,错误subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1只是意味着grep找不到任何东西,因此这是正常行为。
Serge

2
ps.wait()当我们已经有了输出时,为什么需要for。ps.wait.__doc__等待孩子终止,但是孩子的内容似乎已经放入output变量中
Papouche Guinslyzinho

3
@MakisH你看string.find,这有利于被弃用str.find(即方法find上的str对象)。
Taymon

4
注意:如果grep过早死亡;ps如果它产生足够的输出以填充其OS管道缓冲区,则可能会无限期挂起(因为您尚未ps.stdout.close()在父级中调用)。交换开始顺序,以避免发生
JFS

54

或者,您始终可以在子流程对象上使用communication方法。

cmd = "ps -A|grep 'process_name'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

通信方法返回标准输出和标准错误的元组。


3
我认为使用communicate比更好wait出现这样的警告:“当使用stdout = PIPE和/或stderr = PIPE时,这将导致死锁,并且子进程会向管道生成足够的输出,从而阻塞等待OS管道缓冲区接受更多数据的时间。请使用communication()来避免那样。”
Paolo

1
为了澄清Paolo在上面的评论,警告是等待,而不是交流-这就是他说交流更好的原因。
EnemyBagJones

23

请参阅有关使用子流程设置管道的文档:http : //docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

我没有测试下面的代码示例,但是它应该大致是您想要的:

query = "process_name"
ps_process = Popen(["ps", "-A"], stdout=PIPE)
grep_process = Popen(["grep", query], stdin=ps_process.stdout, stdout=PIPE)
ps_process.stdout.close()  # Allow ps_process to receive a SIGPIPE if grep_process exits.
output = grep_process.communicate()[0]

2
在检查这个失败,请参见下面的答案被Taymon的东西,如果没有周围碴工程
艾尔文


6

JKALAVIS解决方案很好,但是我将使用shlex代替SHELL = TRUE进行改进。下面即时查询时间

#!/bin/python
import subprocess
import shlex

cmd = "dig @8.8.4.4 +notcp www.google.com|grep 'Query'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

1
为什么用Shellx胜过Shell?
AFP_555

2
shlex在哪里使用?
3lokh

4

另外,尝试使用'pgrep'命令代替'ps -A | grep 'process_name'


2
如果您想获取进程ID,显然
Shooe 2012年


0

Python 3.5之后,您还可以使用:

    import subprocess

    f = open('test.txt', 'w')
    process = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE, universal_newlines=True)
    f.write(process.stdout)
    f.close()

该命令的执行被阻止,输出将在process.stdout中

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.