1. 程式人生 > >Python subprocess 子程序管理(一)

Python subprocess 子程序管理(一)

最近在改進自動化框架的啟動模組,從而能夠把robot的所有輸出寫入到日誌檔案中以便檢視,也為下一步研究selenium grid打下基礎。在這個過程中看了不少有關python中通過subprocess執行外部命令的資料,所以就順便寫下來以便日後溫習。一下所有的內容都基於Windows中python2.7的環境,Unix和python3中會稍有不同。

在搜尋通過python 執行外部命令的文章中總能看到諸如os.system, os.popen 和 subprocess.Popen區別的文章。這也著實讓我迷惑了一陣,到底用哪一個才是比較好的方案。看了官方的文件之後才豁然開朗。The subprocess

 module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions。答案很明顯,subprocess模組就是用來替換之前的那些舊模組的。所以我們直接學習subprocess就可以了。

在subprocess模組中提供了3個方法和一個類來實現執行管理子程序,官方建議普通的運用中我們可以直接呼叫提供的函式來快速完成子程序的執行,並獲取執行結果。只有在高階應用是才考慮使用Popen類。第一部分先介紹這三個快捷函式。

subprocess.call(args*stdin=Nonestdout=Nonestderr=Noneshell=False)

以下是常用的引數介紹,完全的引數項跟Popen一樣,因為在call的時候並不推薦使用所以就略去了。執行成功會返回returncode屬性。

args: 可以是一個string,陣列或者列表。用來存放需要執行的命令和引數,例如‘echo hello’或者('echo', 'hello')

stdin, stdout,stderr分別就是標準輸出,標準輸入,標準錯誤輸出。如果去預設值則繼承自父程序的相關設定,也可以指向PIPE或一個檔案物件。

shell:布林值,是否呼叫一個shell來執行。當為true時會呼叫系統預設的shell環境來執行命令。對於windows的環境來說,只有當需要執行cmd內建命令的時候才需要設為true。

下面舉兩個shell的例子


這裡運行了cmd的echo來列印hello。如果不把shell設定為True則會丟擲WindowsError,就像在Windows裡直接執行一個沒有後綴的檔案,Windows便不知道如何執行它。shell為True時會呼叫cmd來執行echo命令,自然就沒有問題了。執行成功的話,call返回了returncode 0.

下面再看一個例子,這裡直接執行cmd.exe。執行成功了,顯示了cmd的命令提示符。因為cmd.exe在Windows裡是一個可執行檔案,所以不需要再呼叫cmd去執行他。


再舉一個stdin重定向的例子,先將echo hello存在d:/test.txt. 通過將stdin指向從檔案讀取命令。


subprocess.check_call(args*stdin=Nonestdout=Nonestderr=Noneshell=False)

所有的引數與call一模一樣,就不在累述了。功能上與call大部分一樣,只是當返回的return code不為0時會丟擲CallProcessError,而call不會。如下:


subprocess.check_output(args*stdin=Nonestderr=Noneshell=Falseuniversal_newlines=False)

除了universal_newlines,其他的引數與call一致。universal_newlines為Ture時表示在stdout,stderr指向PIPE或file object時會使用universal_newlines的方式寫入。什麼是universal_newlines呢?請移步這篇blog,很好的介紹了這種方式https://blog.tankywoo.com/2015/01/11/python-universal-newlines.html

從功能上來說它與check_output很相似,不同的是會將子程序的output作為一個byte string返回,而不是列印到標準輸出。從下面這個例子可以看出區別。執行check_output沒有打印出dir命令的結果,而是返回給了dir變數。執行check_call則是直接打印出了dir命令的結果,返回的只是return code的值


注意:

官方特別強調在運用這三個函式時,不要使用stderr=PIPE如下. 主要的原因是如果輸出大量資料超出快取造成管道堵塞的話,會導致死鎖函式會hang在那裡。在這個情況下使用Popen的communicate()方法,會將stderr的內容載入到記憶體中。

Note

Do not use stderr=PIPE with this function as that can deadlock based on the child process error volume. Use Popen with the communicate() method when you need a stderr pipe.


今天就先介紹這三個快捷函式,相信大部分的使用場景這三個函式就能夠搞定了。Popen類在下一篇介紹