使用“subprocess.check_output”时,如何正确引用 python 中的 bash 命令



我正在尝试在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/bashtime是一个关键字,它指示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而不是程序timels作为参数运行。

为什么不需要报价?简单:字符串列表指定应如何拆分命令行。将"time ls"放在列表的单个元素中已经提供了您想要的"引用"。


至于如何获得你想要的输出,由于bash time输出stderr,一个解决方案是将stderr重定向到stdout(并删除ls输出)。

>>> s.check_output(['bash', '-c', "time ls > /dev/null"], stderr=s.STDOUT)
'nrealt0m0.001snusert0m0.000snsyst0m0.000sn'

相关内容

  • 没有找到相关文章

最新更新