Python外壳包装
我正在尝试编写一个简单的Python版本的time
命令行程序,不同之处在于,不是将真实的/ usr/sys时间显示给shell,而是将其记录到数据库中。Python外壳包装
我目前拥有的是:
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
的输出与直接在shell中运行时不同,并且在从Python脚本中的子进程运行时变得混乱?
首先,你为什么要处理与蟒蛇在所有的I/O?只要让子进程的stdout和stderr与python的地方一样。其次,不是实际使用time命令,而是直接从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的内置版本的时间。尝试在shell提示下输入“type -a time”。另外,试试像这样运行你的测试程序:“/ usr/bin/time ./test.py”,你应该看到第二个表单。
你需要编写实时输出:
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()
这不起作用。它仍然阻塞,等到子过程结束后再立即打印所有内容。 – Cerin
良好的通话。完美的作品,比我想象的要简单得多。 – Cerin