检索subprocess.call()的输出

Jef*_*rth 248 python subprocess pipe 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'
>>> 
Run Code Online (Sandbox Code Playgroud)

sar*_*gue 253

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

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

import subprocess

print subprocess.check_output(["ping", "-c", "1", "8.8.8.8"])
Run Code Online (Sandbox Code Playgroud)

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

如下所述,您可以在其他答案中找到更详细的解释.

  • [找到工作代码的另一个答案](http://stackoverflow.com/a/8235171/881224).如果你使用它,请upvote. (37认同)
  • 但请注意,如果进程返回非零退出代码,check_output将抛出异常. (7认同)

Mik*_*ike 196

subprocess.call()只应将输出重定向到文件.

你应该使用subprocess.Popen().然后,您可以传递subprocess.PIPEstderr,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
Run Code Online (Sandbox Code Playgroud)

原因是所使用的类文件对象subprocess.call()必须具有真实的文件描述符,从而实现该fileno()方法.只使用任何类似文件的对象都无法解决问题.

有关详细信息,请参见此处

  • 这个页面http://docs.python.org/library/subprocess.html#module-subprocess不鼓励使用`subprocess.PIPE`,任何想法如何克服这一点? (57认同)
  • @Halst:文档警告`call()调用`PIPE`(在这种情况下不要使用'PIPE`).将'PIPE`与`subprocess.Popen`一起使用是好的,例如,`output,_ = Popen(...,stdout = PIPE).communicate()`正如这个答案所暗示的那样. (19认同)
  • 此外,问题使用subprocess.call指定,Mike的答案实际上是使用Popen,因为subprocess.call只返回返回码,但没有访问任何流的方法.如果使用2.6,如果使用2.7 @Sergi答案则可以使用 (6认同)
  • @NathanBasanese:简而言之:除非你消耗管道,否则不使用`PIPE`.`call()`是`Popen().wait()`因此它不消耗管道(一旦相应的OS管道缓冲区填满,子进程就会永久挂起).`Popen().communic()`如果使用`PIPE`,则从管道写入/读取数据,从而允许子进程继续. (5认同)
  • // , 喔好吧。那讲得通。奇怪的是,它甚至允许使用PIPE作为参数。无论如何,我还是个优秀的StackOverFlow公民,对此提出了一个问题:http://stackoverflow.com/questions/32364849/what-difference-between-subprocess-call-and-subprocess-popen-makes-pipe将您愿意将其作为答案吗? (2认同)

Chi*_*nke 48

对于python 3.5+,建议您使用子进程模块中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)
Run Code Online (Sandbox Code Playgroud)

  • 您应该使用 ``text=True`` 而不是 ``universal_newlines=True`` ,因为前者是为了向后兼容而保留的。 (3认同)
  • “建议使用‘run’函数”——当我使用这些参数时,这对我不起作用,这似乎是 Windows 的问题。我通过在“run”命令中添加“shell=True”解决了这个问题!无论您使用什么操作系统,如果您使用的是 Python 3.7+,请将“stdout=PIPE, stderr=PIPE”替换为“capture_output=True”以添加不会死锁的缓冲区。 (3认同)
  • @Post169 对于 Python 3.7+ 人群来说是一个很好的答案!所以我运行了`rc = subprocess.run(ogrList, capture_output=True)`然后`print("\n", rc.stdout)`并且效果很好!谢谢! (3认同)

Jab*_*bba 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)
Run Code Online (Sandbox Code Playgroud)

我也有一个博客帖子上这里.

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

  • @Jabba由于某种原因除非我将'shell = True`添加到Popen()的参数中,否则它将无法工作,你能解释一下原因吗? (2认同)

Che*_*old 29

我最近才弄清楚如何做到这一点,这里是我当前项目的一些示例代码:

#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 ...
Run Code Online (Sandbox Code Playgroud)

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


jhe*_*dus 16

Ipythonshell中:

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

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


Zag*_*ags 15

以下内容在单个变量中捕获进程的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
Run Code Online (Sandbox Code Playgroud)

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

import shlex
command = shlex.split(command)
Run Code Online (Sandbox Code Playgroud)