2011-10-04 89 views
4

我正在嘗試編寫一個簡單的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腳本中的子進程運行時變得混亂?

回答

2

首先,你爲什麼要處理與蟒蛇在所有的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

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

這不起作用。它仍然阻塞,等到子過程結束後再立即打印所有內容。 – Cerin