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()
。如果可以避免的话,应该没有必要或想要使用rawsubprocess.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")