获取subprocess.call()的输出

335 投票
7 回答
642002 浏览
提问于 2025-04-15 17:36

我该如何获取通过 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 个回答

105

对于Python 3.5或更高版本,建议使用subprocess模块中的run函数。这个函数会返回一个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)
341

如果你使用的是Python 2.7或更高版本,可以用subprocess.check_output这个功能,它基本上就是你想要的(它会把标准输出作为字符串返回)。

这里有个简单的例子(适用于Linux系统;请注意):

import subprocess

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

注意,ping命令在这里用的是Linux的写法(-c表示计数)。如果你在Windows上试这个,记得把它改成-n,这样才能得到相同的结果。

正如下面的评论所说,你可以在这个其他回答中找到更详细的解释。

236

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() 方法。仅仅使用任何文件样的对象是无法达到这个效果的。

想了解更多信息,可以查看 这里

撰写回答