python中的subprocess

 python2.7 源碼中的注釋(由於能力有限,翻譯的不太準確):

這個模組允許您開啟進程、連接輸入、輸出和錯誤的管道,並獲取他們的返回程式碼。這個模組計劃替代一些舊程式碼,如:

os.system、os.spawn*、os.Popen、popen2.* 、commands.*

關於subprocess模組可以用來取代這些模組和功能在下面可以找到

這個模組定義了一個Popen的類:

class 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應該是一個字元串或序列的程式命令及參數。程式通常執行序列或字元串的第一項,但可以通過使用明確的參數進行設置。

在UNIX上,shell = False(默認):在這種情況下,Popen類使用os.execvp()來執行程式的子進程。args應該通常是一個序列。字元串將被視為只有一個字元串的序列(程式執行)。

在UNIX上,shell= True:如果參數是一個字元串,它指定了通過shell執行命令字元串。如果參數是一個序列,第一項指定命令字元串,其他的將被視為附加的shell命令的參數。

在Windows:Popen類通過使用CreateProcess()執行這個子進程來對字元串操作。如果參數是一個序列,它將用list2cmdline方法將其轉換成一個字元串。請注意,並不是所有的MS Windows應用程式解釋命令行用相同的方法:list2cmdline是專為應用程式與MS C使用相同的規則。 

bufsize,如果給定了,與內置行數open()的參數有相同意義:0意味著無緩衝的,1意味著線性緩衝,其他任何正值意味著使用的緩衝區(大約)大小。一個負bufsize意味著使用這個系統默認情況下,這通常意味著完全緩衝。默認值為bufsize是0(無緩衝的)。

stdin、stdout和stderr分別指定執行程式的標準輸入,標準輸出和標準錯誤。有效值是PIPE,現有的文件描述符(正整數),現有文件對象,None。PIPE創建一個新的子管道。None,沒有重定向;子管道將會繼承父管道的文件句柄。此外,標準錯誤可以用STDOUT來定義,表明應用程式應該從STDOUT捕獲到相同的文件句柄的標準錯誤數據。

如果preexec_fn設置為一個可調用對象,該對象將在子進程執行之前調用。

如果close_fds 為True,所有的文件描述符除了0、1和2都會在子進程執行之前關閉。

如果shell是True,將通過shell執行指定的命令。

如果 cwd 不為None,子進程將在執行前切換到 cwd指定的目錄

如果 env 不為空,為新進程定義環境變數

如果 universal_newlines 為 True, 則文件對象標準輸出、標準錯誤輸出以文本文件形式打開, 但是在unix系統中會以n結束,windows中以rn結束。 在python程式中都是看作為n 注意: 這種功能僅僅支援用通用換行符構建的python(默認)。同時文件對象標準輸出、標準輸入、標準錯誤的換行符屬性,不會被communicate()模組所更新。

如果給定了startupinfo and creationflags參數, 將會轉交給底層CreateProcess() 函數,他們可以指定諸如主窗體的外觀、新進程的優先順序之類的屬性(僅支援windows)

這個模組也定義了一些簡短的函數:

call(*popenargs, **kwargs):

    運行帶參數的命令.  等待命令完成後返回返回碼屬性。

    這些參數相對於Popen構造函數是相同的。

    Example:

    retcode = call(["ls", "-l"])

check_call(*popenargs, **kwargs):

    運行帶參數的命令.  等待命令完成.如果退出碼是0則返回,如果是其他則拋出      

    CalledProcessError錯誤,該CalledProcessError 對象就會有返回返回碼屬性

    這些參數相對於Popen構造函數是相同的。

    Example:

    check_call(["ls", "-l"])

check_output(*popenargs, **kwargs):

    運行帶參數的命令並且以位元組字元串來返回。

    如果退出碼是非0則會拋出CalledProcessError。

    CalledProcessError的對象將有返回程式碼在returncode屬性和輸出在output屬性

    這些參數相對於Popen構造函數是相同的。

    Example:

    output = check_output(["ls", "-l", "/dev/null"])

異常處理:

==============

在新程式開始執行之前子進程拋出異常,之後父進程重新拋出異常。此外,異常對象會有一個額外稱為'child_traceback'的屬性,從子進程的角度上看,這是一個包含錯誤資訊的字元串。 

最常見的異常是OSError,比如:執行一個不存在的文件,應用程式會拋出OSError異常

如果Popen被無效的參數調用就會拋出『ValueError』

如果check_call() and check_output()在被調用過程中返回一個非零的返回碼則會拋出『CalledProcessError』

安全

==============

和其他popen函數不同,它不會隱式的執行/bin/sh,這意味著所有的字元,包括shell元字元,可以安全地傳遞給子進程。

Popen 對象

=============

Popen類的實例有以下方法

poll()

    檢查子進程是否終止,返回returncode屬性

wait()

    等待子進程終止。返回returncode屬性。

communicate(input=None)

    與進程相互作用: 發送數據到標準輸入。從標準輸出、標準錯誤讀取數據, 直到到達文件尾。等待進程終止。可選的input參數應該是發送給子進程的字元串,或者如果沒有要發送給子進程的數據那就用None 

    communicate() 返回一個元組 (stdout, stderr). 

    注意:讀取的數據是保存在緩衝區中,因此,如果數據太大或沒有限制則不要使用這個方法

下面的屬性也是有效的:

===================== 

stdin

    如果stdin參數是PIPE,這個屬性是提供輸入到子進程一個文件對象,否則為None

stdout

    如果stdout參數是PIPE , 這個屬性是提供輸出到子進程一個文件對象,否則為None

stderr

     如果stderr參數是PIPE , 這個屬性是提供錯誤輸出到子進程一個文件對象,否則為None

pid

    子進程的PID

returncode

    子進程的返回碼。空值表示進程還沒有結束,一個負值『-N』表示子進程被訊號N所結束(僅unix支援)

用subprocess模組取代舊函數:

====================================================

在本節中, "a ==> b" 意味著 b 可以替代 a.

注意: 如果沒有找到執行程式,所有在本節中的函數都有可能以靜默狀態失敗;這個模組會拋出OSError異常

在以下的例子中, 我們假設subprocess 模組是"from subprocess import *" 這樣導入的:

替代 /bin/sh shell 的引號部分  ---------------------------------  output=`mycmd myarg`  ==>  output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0]      替代 shell 的管道  -------------------------  output=`dmesg | grep hda`  ==>  p1 = Popen(["dmesg"], stdout=PIPE)  p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)  output = p2.communicate()[0]      替代 os.system()  ---------------------  sts = os.system("mycmd" + " myarg")  ==>  p = Popen("mycmd" + " myarg", shell=True)  pid, sts = os.waitpid(p.pid, 0)    注意:    * 通過shell調用程式通常不是必須的    * 查看returncode attribute要比exitstatus容易些.    一個更現實的例子:    try:      retcode = call("mycmd" + " myarg", shell=True)      if retcode < 0:          print >>sys.stderr, "Child was terminated by signal", -retcode      else:          print >>sys.stderr, "Child returned", retcode  except OSError, e:      print >>sys.stderr, "Execution failed:", e      替代 os.spawn*  -------------------  P_NOWAIT example:    pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")  ==>  pid = Popen(["/bin/mycmd", "myarg"]).pid      P_WAIT example:    retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")  ==>  retcode = call(["/bin/mycmd", "myarg"])      Vector example:    os.spawnvp(os.P_NOWAIT, path, args)  ==>  Popen([path] + args[1:])      Environment example:    os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)  ==>  Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})      替代 os.popen*  -------------------  pipe = os.popen("cmd", mode='r', bufsize)  ==>  pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout    pipe = os.popen("cmd", mode='w', bufsize)  ==>  pipe = Popen("cmd", shell=True, bufsize=bufsize, stdin=PIPE).stdin      (child_stdin, child_stdout) = os.popen2("cmd", mode, bufsize)  ==>  p = Popen("cmd", shell=True, bufsize=bufsize,            stdin=PIPE, stdout=PIPE, close_fds=True)  (child_stdin, child_stdout) = (p.stdin, p.stdout)      (child_stdin,   child_stdout,   child_stderr) = os.popen3("cmd", mode, bufsize)  ==>  p = Popen("cmd", shell=True, bufsize=bufsize,            stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)  (child_stdin,   child_stdout,   child_stderr) = (p.stdin, p.stdout, p.stderr)      (child_stdin, child_stdout_and_stderr) = os.popen4("cmd", mode,                                                     bufsize)  ==>  p = Popen("cmd", shell=True, bufsize=bufsize,            stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)  (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)    在 Unix系統中, os.popen2, os.popen3 與 os.popen4 同樣可以在沒有shell介入的情況下直接傳遞給程式  以序列形式執行命令行  這種方法可以用下面的方法替換:    (child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode,                                          bufsize)  ==>  p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE)  (child_stdin, child_stdout) = (p.stdin, p.stdout)    Return code handling translates as follows:    pipe = os.popen("cmd", 'w')  ...  rc = pipe.close()  if rc is not None and rc % 256:      print "There were some errors"  ==>  process = Popen("cmd", 'w', shell=True, stdin=PIPE)  ...  process.stdin.close()  if process.wait() != 0:      print "There were some errors"      替代 popen2.*  ------------------  (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)  ==>  p = Popen(["somestring"], shell=True, bufsize=bufsize            stdin=PIPE, stdout=PIPE, close_fds=True)  (child_stdout, child_stdin) = (p.stdout, p.stdin)    在 Unix系統中, popen2 也可以在沒有shell介入的情況下直接傳遞給程式以序列形式執行命令行.  這種方法可以用下面的方法替換:    (child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize,                                              mode)  ==>  p = Popen(["mycmd", "myarg"], bufsize=bufsize,            stdin=PIPE, stdout=PIPE, close_fds=True)  (child_stdout, child_stdin) = (p.stdout, p.stdin)    The popen2.Popen3 and popen2.Popen4 basically works as subprocess.Popen,  except that:    * subprocess.Popen raises an exception if the execution fails  * the capturestderr argument is replaced with the stderr argument.  * stdin=PIPE and stdout=PIPE must be specified.  * popen2 closes all filedescriptors by default, but you have to specify    close_fds=True with subprocess.Popen.