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”,你应该看到第二个表单。

+0

良好的通话。完美的作品,比我想象的要简单得多。 – Cerin

你需要编写实时输出:

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() 
+0

这不起作用。它仍然阻塞,等到子过程结束后再立即打印所有内容。 – Cerin