由于某种原因,当我从终端运行"time./"时,我得到的格式是:
real ;0m0.090s用户#x09;0.086秒sys ;0m0.004s
但是当我在Python 2.7.6中执行相同的命令时:
result = subprocess.Popen("time ./<binary>", shell = True, stdout = subprocess.PIPE)
当我print(result.stderr)
:时,我得到了这种格式
0.09user 0.00system 0:00.09elapsed
有什么方法可以强制使用第一个(real、user、sys)格式吗?
来自man time
文档:
实用程序完成后,time将所用的总时间、系统开销所消耗的时间以及用于执行实用程序的时间写入标准错误流
加粗强调mine。您捕获的是stdout流,而不是stderr
流,因此无论看到什么输出,都必须是其他东西破坏Python stderr流的结果。
捕获stderr
:
proc = subprocess.Popen("time ./<binary>", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
然后,stderr
变量保持time
命令输出。
如果这种情况继续产生相同的输出,那么/bin/bash
实现有一个内置的time
命令,它会覆盖/usr/bin/time
版本(可能会在一行中输出所有内容)。您可以通过告诉Python使用以下内容来强制使用bash内置:
proc = subprocess.Popen("time ./<binary>", shell=True, executable='/bin/bash',
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
首先:Martijn Pieters关于需要捕获time
的stderr
而不是stdout
的回答是正确的。
此外,至少在较旧版本的Python(如3.1)上,subprocess.Popen
对象包含几个可以被视为"输出"的东西。尝试print
只会导致:
<subprocess.Popen object at 0x2068fd0>
如果以后的版本可以使用print
,则必须对其内容进行一些处理,可能包括对输出进行篡改。
从Popen
对象读取(和打印)
Popen
对象有一个stderr
字段,它是一个可读的、类似文件的对象。您可以像任何其他类似文件的对象一样从中read
,尽管不建议这样做。引用粉红色的安全警告:
警告
使用
communicate()
而不是.stdin.write
、.stdout.read
或.stderr.read
,以避免由于任何其他操作系统管道缓冲区填满并阻塞子进程而导致的死锁。
要打印Popen
的内容,您必须:
communicate()
与子进程,将其返回的2元组(stdout
,stderr
)分配给局部变量。将变量的内容转换为字符串——默认情况下,它是一个
bytes
对象,就好像"文件"是在二进制模式下打开的一样。
下面是一个小程序,它打印shell命令的stderr
输出,而不进行篡改(不包括从ASCII到Unicode的转换)。
#!/usr/bin/env python3
import subprocess
def main():
result = subprocess.Popen(
'time sleep 0.2',
shell=True,
stderr=subprocess.PIPE,
)
stderr = result.communicate()[1]
stderr_text = stderr.decode('us-ascii').rstrip('n')
#print(stderr_text) # Prints all lines at once.
# Or, if you want to process output line-by-line...
lines = stderr_text.split('n')
for line in lines:
print(line)
return
if "__main__" == __name__:
main()
此输出在旧的Fedora Linux系统上,运行bash
,LC_ALL
设置为"C"
:
real#x0009;0m0.201s用户#x0009;0m0.000ssys#x0009;0m0.001s
注意,您需要在脚本的stderr_text = stderr.decode(...)
行周围添加一些错误处理。。。据我所知,time
根据本地化、环境变量等发出非ASCII字符。
备选方案:universal_newlines
您可以使用universal_newlines
选项将一些解码样板保存到Popen
。它自动完成从bytes
到strings
的转换:
如果universal_newlines是
True
,则这些文件对象将使用locale.getpreferredencoding(False)
返回的编码以通用换行模式作为文本流打开。[…]
def main_universal_newlines():
result = subprocess.Popen(
'time sleep 0.2',
shell=True,
stderr=subprocess.PIPE,
universal_newlines=True,
)
stderr_text = result.communicate()[1].rstrip('n')
lines = stderr_text.split('n')
for line in lines:
print(line)
return
请注意,我仍然需要手动剥离最后一个'n'
,以完全匹配shell的输出。