1. 程式人生 > >Python subprocess模組總結

Python subprocess模組總結

http://hackerxu.com/2014/10/09/subprocess.html

subprocess最簡單的用法就是呼叫shell命令了,另外也可以呼叫程式,並且可以通過stdout,stdin和stderr進行互動

subprocess的主類

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引數來指定可執行檔案的路徑。
  • bufsize:指定緩衝。0 無緩衝,1 行緩衝,其他 緩衝區大小,負值 系統緩衝(全緩衝)
  • stdin, stdout, stderr分別表示程式的標準輸入、輸出、錯誤控制代碼。他們可以是PIPE,檔案描述符或檔案物件,也可以設定為None,表示從父程序繼承。
  • preexec_fn只在Unix平臺下有效,用於指定一個可執行物件(callable object),它將在子程序執行之前被呼叫。
  • Close_sfs:在windows平臺下,如果close_fds被設定為True,則新建立的子程序將不會繼承父程序的輸入、輸出、錯誤管道。我們不能將close_fds設定為True同時重定向子程序的標準輸入、輸出與錯誤(stdin, stdout, stderr)。
  • shell設為true,程式將通過shell來執行。
  • cwd用於設定子程序的當前目錄
  • env是字典型別,用於指定子程序的環境變數。如果env = None,子程序的環境變數將從父程序中繼承。
  • Universal_newlines:不同作業系統下,文字的換行符是不一樣的。如:windows下用'/r/n'表示換,而Linux下用'/n'。如果將此引數設定為True,Python統一把這些換行符當作'/n'來處理。startupinfo與createionflags只在windows下用效,它們將被傳遞給底層的CreateProcess()函式,用於設定子程序的一些屬性,如:主視窗的外觀,程序的優先順序等等。
  • startupinfo與createionflags只在windows下有效,它們將被傳遞給底層的CreateProcess()函式,用於設定子程序的一些屬性,如:主視窗的外觀,程序的優先順序等等。

Popen方法

  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資訊。

以上全是抄的

在程式中執行其他程式或shell

可以這樣寫

subprocess.Popen('指令碼/shell', shell=True)

也可以這樣

subprocess.call('指令碼/shell', shell=True)

兩者的區別是前者無阻塞,會和主程式並行執行,後者必須等待命令執行完畢,如果想要前者程式設計阻塞可以這樣

s = subprocess.Popen('指令碼/shell', shell=True)
s.wait()

程式返回執行結果

有時候我們需要程式的返回結果,可以這樣做

>>> s = subprocess.Popen('ls -l', shell=True, stdout=subprocess.PIPE) 
>>> s.communicate() 
('\xe6\x80\xbb\xe7\x94\xa8\xe9\x87\x8f 152\n-rw------- 1 limbo limbo   808  7\xe6\x9c\x88  6 17:46 0000-00-00-welcome-to-jekyll.markdown.erb\ndrwx------ 2 limbo limbo  4096  8\xe6\x9c\x88 15 18:43 arg\ndrwx------ 2 limbo limbo  4096  8\xe6\x9c\x88  7 17:37 argv\ndrwxrwxr-x 2 limbo limbo  4096  9\xe6\x9c\x88 10 15:27 c\ndrwxrwxr-x 3 limbo limbo  4096  9\xe6\x9c\x88 11 14:35 d3\ndrwxrwxr-x 3 limbo limbo  4096  9\xe6\x9n', None)

它會返回一個元組:(stdoutdata, stderrdata)

subprocess還有另一種更簡單方法,效果一樣,它會返回stdout

>>> s = subprocess.check_output('ls -l', shell=True)
>>> s
'\xe6\x80\xbb\xe7\x94\xa8\xe9\x87\x8f 152\n-rw------- 1 limbo limbo   808  7\xe6\x9c\x88  6 17:46 0000-00-00-welcome-to-jekyll.markdown.erb\ndrwx------ 2 limbo limbo  4096  8\xe6\x9c\x88 15 18:43 arg\ndrwx------ 2 limbo limbo  4096  8\xe6\x9c\x88  7 17:37 argv\ndrwxrwxr-x 2 limbo limbo  4096  9\xe6\x9c\x88 10 15:27 c\ndrwxrwxr-x 3 limbo limbo  4096  9\xe6\x9c\x88 11 14:35 d3\ndrwxrwxr-x 3 limbo limbo  4096  9\xe6\x9n'

前者可以實現更多的互動,如stderr和stdin,但是在前面呼叫Popen的時候要實現定義Popen(stdin=subprocess.PIPE, stderr=subprocess)

給子程序輸入

import subprocess
child = subprocess.Popen(["cat"], stdin=subprocess.PIPE)
child.communicate("vamei") 

()不為空,則寫入subprocess.PIPE,為空,則從subprocess.PIPE讀取

subprocess.PIPE

#!/usr/bin/env python
import subprocess
child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
out = child2.communicate()
print out

實際上是這樣的過程

child1.stdout-->subprocess.PIPE

child2.stdin<--subprocess.PIPE

child2.stdout-->subprocess.PIPE

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

subprocess.PIPE實際上為文字流提供一個快取區。直到communicate()方法從PIPE中讀取出PIPE中的文字.要注意的是,communicate()是Popen物件的一個方法,該方法會阻塞父程序,直到子程序完成。

參考資料