打印“time”shell命令的输出而不会丢失格式

时间:2016-06-04 21:59:17

标签: python bash time

出于某种原因,当我从终端运行“time。/”时,我得到这种格式:

real	0m0.090s
user	0m0.086s
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

有什么方法可以强制第一个(真实,用户,系统)格式?

2 个答案:

答案 0 :(得分:3)

来自man time文档:

  

实用程序完成后,时间会将经过的总时间,系统开销所消耗的时间以及执行实用程序所用的时间写入标准错误流。

大胆强调我的。您正在捕获 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()

答案 1 :(得分:3)

首先:Martijn Pieters' answer对于需要捕获time的{​​{1}}而不是stderr是正确的。

此外,至少在像3.1这样的旧版本的Python上,subprocess.Popen object包含几个可以被视为“输出”的东西。尝试stdout只会导致:

print

如果以后的版本是<subprocess.Popen object at 0x2068fd0> - 能够,他们必须对其内容进行一些处理,可能包括修改输出。

print对象

中读取(和打印)

Popen对象有一个stderr field,它是一个可读的文件对象。您可以像其他任何类似文件的对象一样 Popen,但不建议这样做。引用大的粉红色security warning

  

警告

     

使用communicate()而不是.stdin.write.stdout.read.stderr.read来避免由于任何其他操作系统管道缓冲区填满并阻止子进程而导致的死锁。

要打印read的内容,您必须:

  1. communicate()使用子流程,将2元组分配给本地变量(Popenstdout)。

  2. 将变量的内容转换为字符串---默认情况下,它是stderr对象,就像“文件”已在二进制模式下打开一样。

  3. 下面是一个很小的程序,它打印一个shell命令bytes输出而不用修改(不计算从ASCII转换为Unicode并返回)。

    stderr

    此输出位于旧的Fedora Linux系统上,运行#!/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() bash设置为LC_ALL

    real	0m0.201s
    user	0m0.000s
    sys	0m0.001s
    

    请注意,您需要在我的脚本的"C"行周围添加一些错误处理...据我所知,stderr_text = stderr.decode(...)根据本地化,环境变量等发出非ASCII字符

    替代方案:time

    您可以使用universal_newlines option to Popen保存一些解码样板。它自动执行从universal_newlinesbytes的转换:

      

    如果 universal_newlines strings,则这些文件对象将使用universal newlines返回的编码以locale.getpreferredencoding(False)模式作为文本流打开。 [...]

    True

    请注意,我仍然需要手动剥离最后一个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 以完全匹配shell的输出。