Python外壳封装器
我正在尝试写一个简单的Python版本的time
命令行程序,不过它不是把实际的用户时间和系统时间显示在终端上,而是把这些信息记录到一个数据库里。
我现在的代码是:
wrapper.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
的输出和我直接在终端运行时不同,而且在Python脚本中作为子进程运行时输出会变得混乱呢?
2 个回答
0
你需要实时输出结果:
process = subprocess.Popen(shlex.split(command), stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
while True:
output = process.stdout.read(1)
if output == '' and process.poll() != None:
break
if output != '':
sys.stdout.write(output)
sys.stdout.flush()
2
首先,为什么你要用Python来处理输入输出呢?其实可以让子进程的标准输出和错误输出直接和Python的一起处理。其次,不用真的去用时间命令,你可以直接从Python里获取资源使用情况。试试下面这个:
#! /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自带的时间命令。你可以在命令行输入“type -a time”来查看。还有,试着这样运行你的测试程序:“/usr/bin/time ./test.py”,你应该能看到第二种形式的输出。