我正在尝试在python中运行和读取time
命令的输出。问题是time
命令在/bin/sh
和/bin/bash
的工作方式不同,如下所示:
sh $ time ls
..
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 3856maxresident)k
0inputs+0outputs (0major+305minor)pagefaults 0swaps
/bin/bash
版本是:
bash $ time ls
..
real 0m0.003s
user 0m0.000s
sys 0m0.000s
我需要后者,因为它比前者更精确。
因此,我试图将命令与 bash -c '<command>'
包装在 check_output
中,但它给了我这样的错误:
>>> s.check_output(["bash", "-c", "'time ls'"])
bash: time ls: command not found
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/subprocess.py", line 544, in check_output
raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command '['bash', '-c', "'time ls'"]' returned non-zero exit status 127
当我排除额外的报价时,输出不会捕获时序信息:
>>> s.check_output(['bash', '-c', 'time ls'])
real 0m0.002s
user 0m0.000s
sys 0m0.000s
'..'
最后,当我使用executable
参数而不是包装时,输出不会捕获任何内容:
>>> s.check_output(['time', 'ls'], shell=True, executable='/bin/bash')
real 0m0.000s
user 0m0.000s
sys 0m0.000s
我该怎么做?
使用 /bin/sh
时,time ls
运行外部程序/usr/bin/time
(您的路径可能会有所不同),然后运行ls
并将计时信息报告为其标准错误。
对于/bin/bash
,time
是一个关键字,它指示bash
shell本身报告执行ls
到标准错误的计时信息。因此,您需要将 shell 的标准错误(而不是命令)重定向到标准输出,以便check_output
可以捕获它。有点丑,但是
s.check_output('exec 2>&1; time ls >/dev/null 2>&1', executable='/bin/bash', shell=True)
应该工作。exec 2>&1
是让check_output
捕获任何东西的部分。以下ls
重定向用于从捕获的内容中删除ls
的输出;如果您还需要命令输出,则可以删除它们。
该错误是由于在证明列表为命令行时不应引用字符串这一事实引起的。事实上:
>>> s.check_output(['bash', '-c', "time ls"])
real 0m0.002s
user 0m0.000s
sys 0m0.000s
'some content produced by ls'
不会引发任何异常,同时:
>>> s.check_output(['bash', '-c', "'time ls'"])
bash: time ls: comando non trovato
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.3/subprocess.py", line 586, in check_output
raise CalledProcessError(retcode, process.args, output=output)
subprocess.CalledProcessError: Command '['bash', '-c', "'time ls'"]' returned non-zero exit status 127
引发您看到的异常。请注意回溯之前的行:
bash: time ls: comando non trovato
引用'time ls'
bash
搜索程序time ls
而不是程序time
以ls
作为参数运行。
为什么不需要报价?简单:字符串列表指定应如何拆分命令行。将"time ls"
放在列表的单个元素中已经提供了您想要的"引用"。
至于如何获得你想要的输出,由于bash
time
输出stderr
,一个解决方案是将stderr
重定向到stdout
(并删除ls
输出)。
>>> s.check_output(['bash', '-c', "time ls > /dev/null"], stderr=s.STDOUT)
'nrealt0m0.001snusert0m0.000snsyst0m0.000sn'