subprocess的目的就是啓動一個新的進程而且與之通訊。shell
subprocess模塊中只定義了一個類: Popen。可使用Popen來建立進程,並與進程進行復雜的交互。它的構造函數以下:windows
class subprocess.Popen( args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
參數args能夠是字符串或者序列類型(如:list,元組),用於指定進程的可執行文件及其參數。若是是序列類型,第一個元素一般是可執行文件的路徑。咱們也能夠顯式的使用executeable參數來指定可執行文件的路徑。api
subprocess.Popen(["cat","test.txt"])
subprocess.Popen("cat test.txt")
這兩個之中,後者將不會工做。由於若是是一個字符串的話,必須是程序的路徑才能夠。(考慮unix的api函數exec,接受的是字符串
列表)
可是下面的能夠工做
subprocess.Popen("cat test.txt", shell=True)
這是由於它至關於
subprocess.Popen(["/bin/sh", "-c", "cat test.txt"])
在*nix下,當shell=False(默認)時,Popen使用os.execvp()來執行子程序。args通常要是一個【列表】。若是args是個字符串的
話,會被當作是可執行文件的路徑,這樣就不能傳入任何參數了。函數
注意:
shlex.split()能夠被用於序列化複雜的命令參數,好比:unix
>>> shlex.split('ls ps top grep pkill') ['ls', 'ps', 'top', 'grep', 'pkill'] >>>import shlex, subprocess >>>command_line = raw_input() /bin/cat -input test.txt -output "diege.txt" -cmd "echo '$MONEY'" >>>args = shlex.split(command_line) >>> print args ['/bin/cat', '-input', 'test.txt', '-output', 'diege.txt', '-cmd', "echo '$MONEY'"] >>>p=subprocess.Popen(args)
能夠看到,空格分隔的選項(如-input)和參數(如test.txt)會被分割爲列表裏獨立的項,但引號裏的或者轉義過的空格不在此列
。這也有點像大多數shell的行爲。code
在*nix下,當shell=True時,若是arg是個字符串,就使用shell來解釋執行這個字符串。若是args是個列表,則第一項被視爲命令,
其他的都視爲是給shell自己的參數。也就是說,等效於:
subprocess.Popen(['/bin/sh', '-c', args[0], args[1], ...])對象
參數bufsize通常0 無緩衝,1 行緩衝,其餘正值 緩衝區大小,負值 採用默認系統緩衝(通常是全緩衝)繼承
executable通常不用,args字符串或列表第一項表示程序名進程
參數stdin, stdout, stderr分別表示程序的標準輸入、輸出、錯誤句柄。他們能夠是PIPE,文件描述符或文件對象,也能夠設置爲None,表示從父進程繼承。字符串
若是參數shell設爲true,程序將經過shell來執行。
參數env是字典類型,用於指定子進程的環境變量。若是env = None,子進程的環境變量將從父進程中繼承。
subprocess.PIPE
在建立Popen對象時,subprocess.PIPE能夠初始化stdin, stdout或stderr參數。表示與子進程通訊的標準流。
subprocess.STDOUT
建立Popen對象時,用於初始化stderr參數,表示將錯誤經過標準輸出流輸出。
Popen的方法:
Popen.poll()
用於檢查子進程是否已經結束。設置並返回returncode屬性。
Popen.wait()
等待子進程結束。設置並返回returncode屬性。
Popen.communicate(input=None)
與子進程進行交互。向stdin發送數據,或從stdout和stderr中讀取數據。可選參數input指定發送到子進程的參數。Communicate()返回一個元組:(stdoutdata, stderrdata)。注意:若是但願經過進程的stdin向其發送數據,在建立Popen對象的時候,參數stdin必須被設置爲PIPE。一樣,若是但願從stdout和stderr獲取數據,必須將stdout和stderr設置爲PIPE。
Popen.send_signal(signal)
向子進程發送信號。
Popen.terminate()
中止(stop)子進程。在windows平臺下,該方法將調用Windows API TerminateProcess()來結束子進程。
Popen.kill()
殺死子進程。
Popen.pid
獲取子進程的進程ID。
Popen.returncode
獲取進程的返回值。若是進程尚未結束,返回None。
進程通訊:
若是想獲得進程的輸出,管道是個很方便的方法:
p=subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdoutput,erroutput) = p.communicate()
p.communicate會一直等到進程退出,並將標準輸出和標準錯誤輸出返回,這樣就能夠獲得子進程的輸出了。
上面的例子經過communicate給stdin發送數據,而後使用一個tuple接收命令的執行結果。
上面,標準輸出和標準錯誤輸出是分開的,也能夠合併起來,只須要將stderr參數設置爲subprocess.STDOUT就能夠了,這樣子:
p=subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) (stdoutput,erroutput) = p.communicate()
若是你想一行行處理子進程的輸出,也沒有問題:
p=subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while True: buff = p.stdout.readline() if buff == '' and p.poll() != None: break
死鎖
可是若是你使用了管道,而又不去處理管道的輸出,那麼當心點,若是子進程輸出數據過多,死鎖就會發生了,好比下面的用法:
p=subprocess.Popen("longprint", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.wait()
longprint是一個假想的有大量輸出的進程,那麼在個人xp, Python2.5的環境下,當輸出達到4096時,死鎖就發生了。固然,若是咱們用p.stdout.readline或者p.communicate去清理輸出,那麼不管輸出多少,死鎖都是不會發生的。或者咱們不使用管道,好比不作重定向,或者重定向到文件,也都是能夠避免死鎖的。
subprocess還能夠鏈接起來多個命令來執行。
在shell中咱們知道,想要鏈接多個命令可使用管道。
在subprocess中,可使用上一個命令執行的輸出結果做爲下一次執行的輸入。例子以下: