http://backend.blog.163.com/blog/static/2022941262014016710912/
很多開發和營運人員喜歡用python做一些開發或是營運的工作。不可避免要調用系統命令。
調用系統命令的方式有兩種,一種是os.system(CMD),一種是subprocess.Popen(CMD,stdout=what,stderr=what)。
如: import os os.system("echo hi")
或者 import subprocess obj=subprocess.Popen("echo hi")
但是這通常不能滿足要求。我們一般需要解析執行命令之後的輸出,並從輸出中解析出我們想要的資訊。
前一種無法滿足要求,os.system無法有效輸出cmd執行之後的結果。只能使用subprocess的方式。
通常的做法如下:
import subprocess import traceback
try: cmd = "ls -lh" obj = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True) obj.wait() lines = obj.stdout.readlines() if not lines or len(lines) == 0: line = obj.stderr.readlines() print lines except Exception, e: print traceback.format_exc()
這樣做在大多數情況下都不會有問題。但是這裡影藏了潛在的危險。就是會發現有一天程式hang住了。 這可能導致整個應用被掛住。當你費了很大力氣定位問題時,會發現罪魁禍首便是Popen。而令人困惑的 是,這個地方你已經測試過n次了。怎麼會在這裡hang住了呢。
原因是subprocess的PIPE是有大小的。在python2.6.11之前,PIPE的大小為檔案頁的大小(i386上是4096), 2.6.11之後變為65536.因此當輸出內容超過65536,會引起阻塞。因為PIPE已經被塞滿了,無法再塞進更多的 資料。
解決方案是不用subprocess提供的PIPE,而是使用自己建立的流。如此,可以控制流程的大小。不多說,直接 上代碼: import subprocess import traceback import tempfile try: cmd = "ls -lh" out_temp = tempfile.SpooledTemporaryFile(bufsize=10*1000) fileno = out_temp.fileno() obj = subprocess.Popen(cmd,stdout=fileno,stderr=fileno,shell=True) obj.wait() out_temp.seek(0) lines = out_temp.readlines() print lines except Exception, e: print traceback.format_exc() finally: if out_temp: out_temp.close()