检索subprocess.call()的输出

时间:2010-01-03 22:07:06

标签: 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, 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'
>>> 

7 个答案:

答案 0 :(得分:233)

如果你有Python版本&gt; = 2.7,你可以使用subprocess.check_output基本上完全符合你想要的(它将标准输出作为字符串返回)。

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

import subprocess

print subprocess.check_output(["ping", "-c", "1", "8.8.8.8"])

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

如下所述,您可以在this other answer中找到更详细的说明。

答案 1 :(得分:179)

subprocess.call()的输出只能重定向到文件。

您应该使用subprocess.Popen()代替。然后,您可以通过subprocess.PIPE传递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()方法。只使用任何类似文件的对象都无法解决问题。

有关详细信息,请参阅here

答案 2 :(得分:47)

我有以下解决方案。它还捕获退出代码,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)

我还有一篇博文here

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

答案 3 :(得分:39)

对于python 3.5+,建议您使用run function from the subprocess module。这将返回一个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)

答案 4 :(得分:28)

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

#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”的文件对象。从我所知道的,communication()方法只是一种方便的方法来返回输出的元组和你运行的进程的错误。此外,在实例化Popen时运行该过程。

答案 5 :(得分:12)

Ipython shell中:

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

基于sargue的回答。归功于sargue。

答案 6 :(得分:6)

以下在单个变量中捕获进程的stdout和stderr。它与Python 2和3兼容:

from subprocess import check_output, CalledProcessError, STDOUT

command = ["ls", "-l"]
try:
    output = check_output(command, stderr=STDOUT).decode()
    success = True 
except CalledProcessError as e:
    output = e.output.decode()
    success = False

如果您的命令是字符串而不是数组,请在前面加上:

import shlex
command = shlex.split(command)