python模塊subprocess學習

  • subprocess模塊介紹

  subprocess是python建立子進程的工具,其實和c中的fork出一個子進程,而後在子進程中運行exec執行另一個進程很相似。html

  subprocess包中有不少方法建立子進程,這些函數建立子進程的行爲不太同樣,咱們能夠更具需求選擇不一樣的方式來建立子進程。python

  使用subprocess包中的函數建立子進程的時候,要注意:ios

  1) 在建立子進程以後,父進程是否暫停,並等待子進程運行。shell

  2) 函數返回什麼ubuntu

  3) 當returncode不爲0時,父進程如何處理。windows

  • subprecess.call() 

  subprocess.call()
  父進程等待子進程完成
  返回退出信息(returncode,至關於exit code,見Linux進程基礎)緩存

 

 

 

  subprocess.check_call()bash

 

  父進程等待子進程完成app

 

  返回0函數

 

  檢查退出信息,若是returncode不爲0,則舉出錯誤subprocess.CalledProcessError,該對象包含有returncode屬 性,可用try...except...來檢查(見Python錯誤處理)。

 

 

 

  subprocess.check_output()

 

  父進程等待子進程完成

 

  返回子進程向標準輸出的輸出結果

 

  檢查退出信息,若是returncode不爲0,則舉出錯誤subprocess.CalledProcessError,該對象包含有returncode屬性和output屬性,output屬性爲標準輸出的輸出結果,可用try...except...來檢查。

  

複製代碼
 1 #include <iostream>
 2 #include <unistd.h>  3  4 using namespace std;  5  6 int main(int argc, const char *argv[])  7 {  8 cout << "Python is powerful" << endl;  9 for (int i = 0; i < argc; i++) 10  { 11 cout << argv[i] << endl; 12  } 13 sleep(10); 14 return 0; 15 } 16 ~ 
複製代碼
複製代碼
複製代碼
 1 #!/usr/bin/env python  2  3 import subprocess  4  5 returnCode = subprocess.call('ls -l',shell=True) 
//咱們使用了shell=True這個參數。這個時候,咱們使用一整個字符串,而不是一個表來運行子進程。Python將先運行一個shell,再用這個shell來解釋這整個字符串。
6 print "returnCode:",returnCode 7 8 returnCode = subprocess.call(['ls','-l'])
//咱們將程序名(ls)和所帶的參數(-l)一塊兒放在一個表中傳遞給subprocess.call()
 9 print "returnCode:",returnCode 10 11 returnCode = subprocess.call(['./app','-a','-b','-c','-d']) 
//app也將參數和app自己以一個列表爲傳遞過去
12 print "returnCode:",returnCode
複製代碼

 

執行結果:

複製代碼
複製代碼
yca@ubuntu:~/Desktop/go$ ./assert.py 
total 1256
-rwxr-xr-x 1 yca yca    7785 2013-05-07 20:02 app -rw-r--r-- 1 yca yca 221 2013-05-07 20:01 app.cpp -rwxr-xr-x 1 yca yca 217 2013-05-07 20:40 assert.py -rwxr-xr-x 1 yca yca 1256270 2013-04-28 02:30 hello -rw-r--r-- 1 yca yca 396 2013-05-01 19:59 hello.go -rw-r--r-- 1 yca yca 918 2013-05-07 01:08 HelloWorld.go -rw-r--r-- 1 yca yca 556 2013-05-07 02:43 map.go returnCode: 0 Python is powerful ./app -a -b -c -d returnCode: 0
複製代碼

 

  • subprocess.Popen()

 上面三個函數都是對subprocess.Popen的封裝,這些封裝的目的是爲了讓咱們容易使用子進程。當咱們想要更個性化咱們的需求的時候,就要轉向Popen類,該類生成的對象用來表明子進程。

  與上面的封裝不一樣,Popen對象建立後,主程序不會自動等待子進程完成。咱們必須調用對象的wait()方法,父進程纔會等待 (也就是阻塞block):

  

複製代碼
1 #!/usr/bin/env python 2 3 import subprocess 4 5 returnCode = subprocess.Popen(['./app','-a','-b','-c','-d']) 6 print "parent process"
複製代碼

 

複製代碼
yca@ubuntu:~/Desktop/go$ ./assert.py 
parent process
yca@ubuntu:~/Desktop/go$ Python is powerful ./app -a -b -c -d
複製代碼

從運行結果中看到,父進程在開啓子進程以後並無等待child的完成,而是直接運行print。

  

複製代碼
1 #!/usr/bin/env python 2 3 import subprocess 4 5 child = subprocess.Popen(['./app','-a','-b','-c','-d']) 6 returnCode = child.wait() 7 print "returnCode:",returnCode
8 print "parent process"
複製代碼
複製代碼
yca@ubuntu:~/Desktop/go$ ./assert.py 
Python is powerful
./app -a -b -c -d
returnCode:0 parent process
複製代碼

很明顯父進程在等待子進程執行完畢,纔開始執行

此外,你還能夠在父進程中對子進程進行其它操做,好比咱們上面例子中的child對象:

child.poll()           # 檢查子進程狀態

child.kill()           # 終止子進程

child.send_signal()    # 向子進程發送信號

child.terminate()      # 終止子進程

 

複製代碼
1.Popen.poll():用於檢查子進程是否已經結束。設置並返回returncode屬性。 2.Popen.wait():等待子進程結束。設置並返回returncode屬性。 3.Popen.communicate(input=None):與子進程進行交互。向stdin發送數據,或從stdout和stderr中讀取數據。可選參數input指定發送到子進程的參數。Communicate()返回一個元組:(stdoutdata, stderrdata)。注意:若是但願經過進程的stdin向其發送數據,在建立Popen對象的時候,參數stdin必須被設置爲PIPE。一樣,若是但願從stdout和stderr獲取數據,必須將stdout和stderr設置爲PIPE。 4.Popen.send_signal(signal):向子進程發送信號。 5.Popen.terminate():中止(stop)子進程。在windows平臺下,該方法將調用Windows API TerminateProcess()來結束子進程。 6.Popen.kill():殺死子進程。 7.Popen.stdin:若是在建立Popen對象是,參數stdin被設置爲PIPE,Popen.stdin將返回一個文件對象用於策子進程發送指令。不然返回None。 8.Popen.stdout:若是在建立Popen對象是,參數stdout被設置爲PIPE,Popen.stdout將返回一個文件對象用於策子進程發送指令。不然返回None。 9.Popen.stderr:若是在建立Popen對象是,參數stdout被設置爲PIPE,Popen.stdout將返回一個文件對象用於策子進程發送指令。不然返回None。 10.Popen.pid:獲取子進程的進程ID。 11.Popen.returncode:獲取進程的返回值。若是進程尚未結束,返回None。 12.subprocess.call(*popenargs, **kwargs):運行命令。該函數將一直等待到子進程運行結束,並返回進程的returncode。文章一開始的例子就演示了call函數。若是子進程不須要進行交互,就可使用該函數來建立。 13.subprocess.check_call(*popenargs, **kwargs):與subprocess.call(*popenargs, **kwargs)功能同樣,只是若是子進程返回的returncode不爲0的話,將觸發CalledProcessError異常。在異常對象中,包括進程的returncode信息。
複製代碼

子進程的PID存儲在child.pid

 

複製代碼
Popen對象
Popen對象有如下方法:
Popen.poll()
檢查子進程是否已結束,設置並返回 returncode 屬性。
Popen.wait()
等待子進程結束,設置並返回 returncode 屬性。
注意:若是子進程輸出了大量數據到stdout或者stderr的管道,並達到了系統 pipe的緩存大小的話,子進程會等待父進程讀取管道,而父進程此時正wait着的話,將會產生傳說中的死鎖,後果是很是嚴重滴。建議使用communicate()來 避免這種狀況的發生。
Popen.communicate(input=None) 和子進程交互:發送數據到stdin,並從stdout和stderr讀數據,直到收到EOF。等待子進程結束。可選的input若有 有的話,要爲字符串類型。 此函數返回一個元組: (stdoutdata, stderrdata) 。 注意,要給子進程的stdin發送數據,則Popen的時候,stdin要爲PIPE;同理,要能夠收數據的話,stdout或者stderr也要爲 PIPE。 注意:讀到的數據會被緩存在內存裏,因此數據量很是大的時候要當心了。 Popen.send_signal(signal) 給子進程發送signal信號量。 注意:windows下目前只支持發送SIGTERM,等效於下面的terminate()。 Popen.terminate() 中止子進程。Posix下是發送SIGTERM信號。windows下是調用TerminateProcess()這 個API。 Popen.kill() 殺死子進程。Posix下是發送SIGKILL信號。windows下和terminate()無異。 Popen.stdin 若是stdin參數是PIPE,此屬性就是一個文件對象,不然爲None。 Popen.stdout 若是stdout參數是PIPE,此屬性就是一個文件對象,不然爲None。 Popen.stderr 若是stderr參數是PIPE,此屬性就是一個文件對象,不然爲None。 Popen.pid 子進程的進程號。注意,若是shell參數爲True,這屬性指的是子shell的進程號。 Popen.returncode 子程序的返回值,由poll()或者wait()設置,間接地也由communicate()設置。 若是爲None,表示子進程還沒終止。 若是爲負數-N的話,表示子進程被N號信號終止。(僅限*nux)
複製代碼

http://blog.csdn.net/mr_jj_lian/article/details/6936984

3. 子進程的文本流控制

(沿用child子進程) 子進程的標準輸入,標準輸出和標準錯誤也能夠經過以下屬性表示:

child.stdin

child.stdout

child.stderr

 

咱們能夠在Popen()創建子進程的時候改變標準輸入、標準輸出和標準錯誤,並能夠利用subprocess.PIPE將多個子進程的輸入和輸出鏈接在一塊兒,構成管道(pipe):

複製代碼
1 #!/usr/bin/env python 2 3 import subprocess 4 5 child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE) 6 child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE) 7 out = child2.communicate() 8 print out 
複製代碼

child1.stdout-->subprocess.PIPE

child2.stdin<--subprocess.PIPE        

child2.stdout-->subprocess.PIPE

至關於將child1.stdout-->child2.stdin->child2.stdout->subprocess.PIPE

subprocess.PIPE實際上爲文本流提供一個緩存區。child1的stdout將文本輸出到緩存區,隨後child2的stdin從該PIPE中將文本讀取走。child2的輸出文本也被存放在PIPE中,直到communicate()方法從PIPE中讀取出PIPE中的文本。

要注意的是,communicate()是Popen對象的一個方法,該方法會阻塞父進程,直到子進程完成。

 

咱們還能夠利用communicate()方法來使用PIPE給子進程輸入:

 

1 import subprocess 2 child = subprocess.Popen(["cat"], stdin=subprocess.PIPE) 3 child.communicate("vamei") //()不爲空,則寫入subprocess.PIPE,爲空,則從subprocess.PIPE讀取
subprocess.PIPE-->child.stdin

commiuncate至關於寫入subprocess.PIPE,而後child從subprocess.PIPE讀取

  • returnCode

  執行子進程後的返回值是從何而來呢?經過exit的返回值獲得

  

1 #!/bin/bash 2 3 echo "hello" 4 exit 1 5 ~ 

 

 

 

複製代碼
1 #!/usr/bin/env python 2 3 import subprocess 4 5 child = subprocess.Popen(["./shell.sh"], stdout=subprocess.PIPE) 6 returnCode = child.wait() 7 print "returnCode:",returnCode 8 stdout = child.communicate() 9 print stdout
複製代碼

 

yca@ubuntu:~/Desktop/go$ ./assert.py 
returnCode: 1 ('hello\n', None)
相關文章
相關標籤/搜索