我正在尝试编写一个简单的 Python 版本的 time
命令行程序,除了它不会向 shell 显示真实/usr/sys 时间,而是将它记录到一个数据库。
我目前拥有的是:
包装器.py
#!/usr/bin/python
import sys
from subprocess import Popen, PIPE
cmd = 'time ' + (' '.join(['"%s"' % v if ' ' in v else v for v in sys.argv[1:]]))
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
print p.stdout.read()
print p.stderr.read()
为简单起见,我排除了数据库插入代码。
但是,为了说明一个问题,我使用了测试脚本:
#!/usr/bin/python
import time
for i in xrange(3):
print i
time.sleep(1)
如果我运行 wrapper.py python delay.py
,我希望看到秒数实时打印出来,然后是类似的内容:
real 0m3.057s
user 0m0.030s
sys 0m0.000s
相反,我在 3 秒内没有输出,然后打印出来:
0
1
2
0.02user 0.00system 0:03.03elapsed 0%CPU (0avgtext+0avgdata 21632maxresident)k
0inputs+0outputs (0major+1514minor)pagefaults 0swaps
您如何实时读取和打印子流程的输出?
此外,为什么 time
的输出与我直接在 shell 中运行它时的输出不同,而当从 Python 脚本中的子进程运行时变得困惑?
最佳答案
首先,你为什么要用 python 处理 I/O?就让子进程的stdout和stderr去到和python一样的地方就行了。其次,您可以直接从 python 检索资源,而不是实际使用 time 命令。尝试这样的事情:
#! /usr/bin/python
import os
import resource
import sys
import time
cmd = ' '.join(sys.argv[1:])
stime = time.time()
os.system(cmd) # fire off the command
etime = time.time()
# now get the resource utilization
r = resource.getrusage(resource.RUSAGE_CHILDREN)
user_time = r.ru_utime
sys_time = r.ru_stime
# resource doesn't know "clock" time, so we'll just figure that ourselves
real_time = etime - stime
print "real\t" + str(real_time)
print "user\t" + str(user_time)
print "sys\t" + str(sys_time)
这会以秒为单位打印时间。如果您真的希望它们看起来像时间命令,您可以相应地设置它们的格式。
要回答问题的第二部分,实际上有不同的“时间”命令。当您将它作为 python 的子项运行时,您将获得/usr/bin/time 的输出。当您手动运行它时,您将获得 shell 的内置时间版本。尝试在 shell 提示符下键入“type -a time”。另外,尝试像这样运行您的测试程序:“/usr/bin/time ./test.py”,您应该会看到第二种形式。
关于Python 外壳包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7652161/