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= 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中以\r\n結束。 在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 對象就會有傳回傳回碼屬性
check_call(["ls", "-l"])
check_output(*popenargs, **kwargs):
運作帶參數的指令并且以位元組字元串來傳回。
如果退出碼是非0則會抛出CalledProcessError。
CalledProcessError的對象将有傳回代碼在returncode屬性和輸出在output屬性
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.