Python 正在检索subprocess.call()的输出

Python 正在检索subprocess.call()的输出,python,pipe,subprocess,stringio,Python,Pipe,Subprocess,Stringio,如何使用subprocess.call()获取流程运行的输出 将StringIO.StringIO对象传递给stdout会出现以下错误: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 444

如何使用
subprocess.call()
获取流程运行的输出

StringIO.StringIO
对象传递给
stdout
会出现以下错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 444, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 588, in __init__
    errread, errwrite) = self._get_handles(stdin, stdout, stderr)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 945, in _get_handles
    c2pwrite = stdout.fileno()
AttributeError: StringIO instance has no attribute 'fileno'
>>> 
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py”,第444行,在调用中
返回Popen(*popenargs,**kwargs)。等待()
文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py”,第588行,在__
errread,errwrite)=self.\u获取\u句柄(标准输入、标准输出、标准输出)
文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py”,第945行,位于“获取”句柄中
c2pwrite=stdout.fileno()
AttributeError:StringIO实例没有属性“fileno”
>>> 

子流程调用()的输出只应重定向到文件

您应该改用
subprocess.Popen()
。然后,您可以传递stderr、stdout和/或stdin参数的
子流程管道
,并使用
communicate()
方法从管道中读取:

from subprocess import Popen, PIPE

p = Popen(['program', 'arg1'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = p.communicate(b"input data that is passed to subprocess' stdin")
rc = p.returncode
原因是
subprocess.call()
使用的类文件对象必须具有真实的文件描述符,从而实现
fileno()
方法。仅仅使用任何类似文件的对象都不会奏效


有关更多信息,请参阅。

我最近刚刚想出了如何做到这一点,下面是我当前项目中的一些示例代码:

#Getting the random picture.
#First find all pictures:
import shlex, subprocess
cmd = 'find ../Pictures/ -regex ".*\(JPG\|NEF\|jpg\)" '
#cmd = raw_input("shell:")
args = shlex.split(cmd)
output,error = subprocess.Popen(args,stdout = subprocess.PIPE, stderr= subprocess.PIPE).communicate()
#Another way to get output
#output = subprocess.Popen(args,stdout = subprocess.PIPE).stdout
ber = raw_input("search complete, display results?")
print output
#... and on to the selection process ...

现在,命令的输出存储在变量“output”中。“stdout=subprocess.PIPE”告诉类从Popen中创建一个名为“stdout”的文件对象。据我所知,communicate()方法只是一种方便的方法,用于返回输出的元组和运行的进程中的错误。此外,在实例化Popen时也会运行该过程。

如果您的Python版本>=2.7,则可以使用它,它基本上完全满足您的需要(它以字符串形式返回标准输出)

简单示例(linux版本,请参见注释):

请注意,ping命令使用linux表示法(
-c
表示计数)。如果您在Windows上尝试此操作,请记住将其更改为
-n
,以获得相同的结果


如下文所述,您可以在中找到更详细的解释。

我有以下解决方案。它捕获执行的外部命令的退出代码、stdout和stderr:

import shlex
from subprocess import Popen, PIPE

def get_exitcode_stdout_stderr(cmd):
    """
    Execute the external command and get its exitcode, stdout and stderr.
    """
    args = shlex.split(cmd)

    proc = Popen(args, stdout=PIPE, stderr=PIPE)
    out, err = proc.communicate()
    exitcode = proc.returncode
    #
    return exitcode, out, err

cmd = "..."  # arbitrary external command, e.g. "python mytest.py"
exitcode, out, err = get_exitcode_stdout_stderr(cmd)
我也有一篇关于它的博客文章


编辑:该解决方案已更新为不需要写入temp的较新解决方案。文件。

Ipython
shell中:

In [8]: import subprocess
In [9]: s=subprocess.check_output(["echo", "Hello World!"])
In [10]: s
Out[10]: 'Hello World!\n'

根据萨格的回答。归功于sargue。

对于python 3.5+,建议您使用。这将返回一个
CompletedProcess
对象,您可以从中轻松获得输出和返回代码

from subprocess import PIPE, run

command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)

关键是使用函数
子流程。检查\u coutput

例如,下面的函数捕获进程的stdout和stderr,并返回它们以及调用是否成功。它与Python 2和3兼容:

from subprocess import check_output, CalledProcessError, STDOUT

def system_call(command)
    try:
        output = check_output(command, stderr=STDOUT).decode()
        success = True 
    except CalledProcessError as e:
        output = e.output.decode()
        success = False
    return output, success

output, success = system_call(["ls", "-l"])
如果要将命令作为字符串而不是数组传递,请使用以下版本:

from subprocess import check_output, CalledProcessError, STDOUT
import shlex

def system_call(command)
    command = shlex.split(command)
    try:
        output = check_output(command, stderr=STDOUT).decode()
        success = True 
    except CalledProcessError as e:
        output = e.output.decode()
        success = False
    return output, success

output, success = system_call("ls -l")

迈克的回答是正确的。请注意,
StringIO
在大多数情况下都像文件一样工作,但并非全部。它在您的情况下不起作用,因为在某些情况下,
多处理
模块假定实际文件。这可能已经被修复:请参阅以了解相关的错误。实际上,
communicate()
使用了
select.select()
,它只接受文件描述符,因此它不是真正的错误。当我第一次遇到它时,我被它弄糊涂了,探索subprocess.py的深度教会了我很多!。我认为这样做会更简单,就像Python3.5一样。当我有机会的时候,我会添加一个答案。注意,被接受的答案已经过时了。Python2.7的简单答案是
子流程;在Python 3.5+中,您还需要查看
subprocess.run()
。如果可以避免的话,应该没有必要或想要使用raw
subprocess.Popen()
,尽管一些更复杂的用例需要它(然后你必须自己做所需的管道)。对于不那么琐碎的情况,有一些很好的资源。本页不鼓励使用
subprocess.PIPE
,有什么办法可以克服这个问题吗?另外,问题特别是使用subprocess.call,Mike的答案是使用Popen,实际上,作为subprocess.call只返回返回代码,但不能访问任何流。如果使用2.6,如果使用2.7@Sergi,答案可能是used@Halst:对于
call()
call(在这种情况下,不要使用
PIPE
),文档会对
PIPE
发出警告。将
管道
子流程.Popen
一起使用是可以的,例如,
输出,=Popen(…,stdout=PIPE).communicate()
,正如这个答案所示。@NathanBasanese:简而言之:除非您使用管道,否则不要使用
管道
call()
Popen().wait()
,因此它不会消耗管道(只要相应的操作系统管道缓冲区填满,子进程就会永远挂起)
Popen().communicate()
如果使用
PIPE
,则从管道写入/读取数据,从而允许子进程继续。//,啊,好的。这是有道理的。奇怪的是,它甚至允许管道作为参数,然后。无论如何,我是一个好公民,但是,并提出了一个问题:你愿意把它作为答案吗?。如果您使用了,请向上投票。但请注意,如果进程返回非零退出代码,check\u output将引发异常。请注意,
check\u output
run
时遇到管道填充问题,因为它只是调用
run
。因此,如果有一个进程生成更多的输出,它将无限期地挂起。来自和答案的
Popen
解决方案工作得更好,但另一个答案不行
from subprocess import check_output, CalledProcessError, STDOUT
import shlex

def system_call(command)
    command = shlex.split(command)
    try:
        output = check_output(command, stderr=STDOUT).decode()
        success = True 
    except CalledProcessError as e:
        output = e.output.decode()
        success = False
    return output, success

output, success = system_call("ls -l")