python模塊subprocess學習


  • subprocess模塊介紹

  subprocess是python創建子進程的工具,其實和c中的fork出一個子進程,然后在子進程中運行exec執行另外一個進程很類似。

  subprocess包中有很多方法創建子進程,這些函數創建子進程的行為不太一樣,我們可以更具需求選擇不同的方式來創建子進程。

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

  1) 在創建子進程之后,父進程是否暫停,並等待子進程運行。

  2) 函數返回什么

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

  • subprecess.call() 

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

 

 

 

  subprocess.check_call()

 

  父進程等待子進程完成

 

  返回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)

 

 









 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM