Python中subprocess模塊的用法詳解
Python subprocess模塊
subprocess是用于啟動進(jìn)程,并與進(jìn)程通信的模塊。
格式
該模塊定義了一個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):
參數(shù)釋義:
args
應(yīng)該是字符串或程序參數(shù)序列,要執(zhí)行的程序通常是args序列或字符串中的第一項,但可以使用
executable參數(shù)顯式設(shè)置。
在UNIX 上,當(dāng) shell=False(默認(rèn)), 類Popen 用 os.execvp() 來執(zhí)行子程序,args通常應(yīng)該是一個序列,如果args是一個字符串,它也會被視為只有一個元素的序列。
在UNIX 上,當(dāng) shell=True,如果 args 是字符串,它將作為命令行字符串通過shell 執(zhí)行;如果是一個序列,它的第一項將作為命令行字符串,其他項將被視為附加的shell參數(shù)。
在 Windows 上,類Popen 用 CreateProcess() 來執(zhí)行子程序,它以字符串作為參數(shù)。
如果args是一個序列,它將使用 list2cmdline 方法轉(zhuǎn)換為字符串。需要注意的是,并非所有MS Windows應(yīng)用程序都以相同的方式解釋命令行,list2cmdline 是為使用與MS C運行規(guī)則相同的應(yīng)用程序而設(shè)計的。
bufsize
如果被賦值,值將作為內(nèi)建函數(shù) open() 的參數(shù),0意味著無緩沖,1就是行緩沖,任何其他正值意味著使用與該值大小接近的緩沖區(qū)。負(fù)bufsize意味著使用系統(tǒng)默認(rèn)值,這通常意味著完全緩沖。 bufsize的默認(rèn)值為0(無緩沖)。
stdin, stdout and stderr
分別代表子程序的標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出,標(biāo)準(zhǔn)錯誤輸出的文件句柄。
有效值為PIPE、現(xiàn)有文件描述符(正整數(shù))、現(xiàn)有文件對象和None。若賦值為PIPE ,就會為子程序創(chuàng)建新管道 ;若為None,不會發(fā)生重定向,子程序的文件句柄將從父程序繼承。
另外,stderr可以是STDOUT,這表明子程序的錯誤數(shù)據(jù)可以被獲得并發(fā)送到stdout輸出。
preexec_fn 如果preexec_fn設(shè)置為可調(diào)用對象,則在執(zhí)行子進(jìn)程之前,將在子進(jìn)程中調(diào)用此對象。
close_fds 若為true,則在執(zhí)行子進(jìn)程之前將關(guān)閉除0,1和2之外的所有文件描述符。
shell 若為true,則將通過shell執(zhí)行指定的命令。
cwd 若不是None,在執(zhí)行子進(jìn)程之前,當(dāng)前目錄將更改為cwd。
env 若不是None,它將為新進(jìn)程指定環(huán)境變量。
universal_newlines 文件對象stdout和stderr作為文本文件打開,但可以通過 '\n' (Unix), '\r' (Mac), '\r\n' (Win)斷行。所有這些外部表示都被Python程序視為'\n'。注意:僅當(dāng)Python使用通用換行支持(默認(rèn))構(gòu)建時,此功能才可用。注意這些特征只在python支持通用換行的時候有效(默認(rèn)支持)。
此外,communication() 方法不會更新文件對象stdout,stdin和stderr的換行屬性。
startupinfo, creationflags 如果給定,將傳遞給底層的 CreateProcess() 函數(shù)。它可以指定主窗口的外觀和新進(jìn)程的優(yōu)先級等內(nèi)容。(僅限Windows)
該模塊還定義了兩個快捷功能:
call(*args, **kwargs):
使用參數(shù)運行命令。等待命令完成,然后返回returncode屬性。
參數(shù)與Popen構(gòu)造函數(shù)相同。例:
retcode = call(["ls", "-l"])
異常
在新程序開始執(zhí)行之前,子進(jìn)程中引發(fā)的異常將在父進(jìn)程中重新引發(fā)。此外,異常對象將有一個名為'child_traceback'的額外屬性,該屬性是一個包含來自子進(jìn)程視點的回溯信息的字符串。
引發(fā)的最常見異常是OSError。例如,在嘗試執(zhí)行不存在的文件時會發(fā)生這種情況。應(yīng)用程序應(yīng)當(dāng)對OSErrors作出處理。
如果使用無效參數(shù)調(diào)用Popen,則會引發(fā)ValueError。
安全性
與其他一些 popen 函數(shù)不同,此實現(xiàn)永遠(yuǎn)不會隱式調(diào)用/bin/sh。
這意味著所有字符(包括shell元字符)都可以安全地傳遞給子進(jìn)程。
Popen 對象
Popen類的實例具有以下方法:
Popen.poll():
檢查子進(jìn)程是否已終止。終止則返回returncode屬性;否則,返回None。
Popen.wait(timeout=None):
等待子進(jìn)程終止,返回returncode屬性。
如果進(jìn)程在超時秒后沒有終止,則引發(fā) TimeoutExpired 異常。捕獲此異常并重試等待將會更安全。
注意:當(dāng)使用stdout = PIPE或stderr = PIPE,并且子進(jìn)程生成太多輸出以致于阻止了等待OS管道緩沖區(qū)接受更多數(shù)據(jù)時,將導(dǎo)致死鎖。使用管道時可以使用 Popen.communicate() 來避免這種情況。
注意:該功能使用忙循環(huán)(非阻塞呼叫和短暫睡眠)實現(xiàn)。
在Python3.3中添加了timeout參數(shù)。
從Python3.4開始不推薦使用endtime參數(shù)。這是無意中暴露在3.3中,但沒有記錄,因為它是私人內(nèi)部使用。請改用timeout 。
Popen.communicate(input=None, timeout=None):
與進(jìn)程交互:將數(shù)據(jù)發(fā)送到stdin。從stdout和stderr讀取數(shù)據(jù),直到達(dá)到文件結(jié)尾。等待進(jìn)程終止??蛇x的input參數(shù)應(yīng)該是要發(fā)送到子進(jìn)程的數(shù)據(jù),如果沒有數(shù)據(jù)需要發(fā)送給子進(jìn)程,則設(shè)為None。如果在文本(text)模式下打開流,則input參數(shù)必須是字符串(string);否則,它必須是字節(jié)(bytes)。
communic()返回一個 tuple(stdout_data, stderr_data) 。如果在文本模式下打開流,則數(shù)據(jù)將是字符串;否則,是字節(jié)。
注意:如果要將數(shù)據(jù)發(fā)送到進(jìn)程的stdin,則需要使用stdin = PIPE創(chuàng)建Popen對象。同樣,要在結(jié)果元組(tuple)中獲取除None之外的任何內(nèi)容,還需要設(shè)置stdout = PIPE and/or stderr = PIPE。
如果進(jìn)程在超時(timeout)秒后沒有終止,則會引發(fā)TimeoutExpired異常。捕獲此異常并重試通信不會丟失任何輸出。
如果超時到期,則子進(jìn)程不會被終止,因此為了正確清理,行為良好的應(yīng)用程序應(yīng)該終止子進(jìn)程并完成通信:
proc = subprocess.Popen(...) try: outs, errs = proc.communicate(timeout=15) except TimeoutExpired: proc.kill() outs, errs = proc.communicate()
注意:讀取的數(shù)據(jù)緩沖在內(nèi)存中,因此如果數(shù)據(jù)大小很大或不受限制,請不要使用此方法。
在Python3.3中添加了timeout參數(shù)。
Popen.send_signal(signal):
向子進(jìn)程發(fā)送signal信號。
注意:在 Windows 上,SIGTERM和terminate() 的作用相同??梢詫?CTRL_C_EVENT 和 CTRL_BREAK_EVENT 發(fā)送到使用 creationflags 參數(shù)啟動的進(jìn)程,該參數(shù)包括 CREATE_NEW_PROCESS_GROUP 。
Popen.terminate():
終止(stop)子進(jìn)程。在Posix OSs上,該方法將SIGTERM發(fā)送給子進(jìn)程。在Windows上,調(diào)用Win32 API函數(shù)TerminateProcess() 來停止子進(jìn)程。
Popen.kill():
殺死子進(jìn)程。在Posix OSs上,該方法將 SIGKILL 發(fā)送給子進(jìn)程。在Windows上,kill() 和terminate() 的作用相同。
還提供以下屬性:
Popen.args:
args參數(shù)傳遞給Popen 程序參數(shù)序列或單個字符串。
Python3.3中的新功能。
Popen.stdin:
如果stdin參數(shù)是PIPE,則此屬性是open() 返回的可寫流對象。如果指定了encoding或errors參數(shù)或者universal_newlines參數(shù)為True,則流是文本流,否則它是字節(jié)流。如果stdin參數(shù)不是PIPE,則此屬性為None。
obj.stdin.write(" args ")
Popen.stdout:
如果stdout參數(shù)是PIPE,則此屬性是open() 返回的可讀流對象。從流中讀取提供子進(jìn)程的輸出。如果指定了encoding或errors參數(shù)或者universal_newlines參數(shù)為True,則流是文本流,否則它是字節(jié)流。如果stdout參數(shù)不是PIPE,則此屬性為None。
obj.stdout.read()
Popen.stderr:
如果stderr參數(shù)是PIPE,則此屬性是open() 返回的可讀流對象。從流中讀取提供子進(jìn)程的錯誤輸出。如果指定了encoding或errors參數(shù)或者universal_newlines參數(shù)為True,則流是文本流,否則它是字節(jié)流。如果stderr參數(shù)不是PIPE,則此屬性為None。
警告:使用 communic() 而不是 .stdin.write,.stdout.read 或 .stderr.read 來避免由于任何其他OS管道緩沖區(qū)填滿和阻止子進(jìn)程而導(dǎo)致的死鎖。
Popen.pid:
子進(jìn)程的進(jìn)程ID。
注意:如果將shell參數(shù)設(shè)置為True,則這是生成的shell的進(jìn)程ID。
Popen.returncode:
子進(jìn)程返回碼,由poll() 和wait() 設(shè)置(間接通過communic())。 None 表示該進(jìn)程尚未終止,負(fù)值 N 表示子進(jìn)程被信號 N 終止(僅限POSIX)。
- returncode=0 表示執(zhí)行成功
- returncode=127 表示語句為空串
- returncode=17 表示找不到表
- returncode=64 表示缺失關(guān)鍵字
- returncode=41 表示查詢的字段不存在
例如:
import os import shlex import signal import subprocess shell_cmd = 'ping www.baidu.com' cmd = shlex.split(shell_cmd) p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # ***CTRL_C信號*** # os.kill(p.pid, signal.CTRL_C_EVENT) # p.send_signal(signal.CTRL_C_EVENT) # ***SIGTERM信號*** # p.send_signal(signal.SIGTERM) # p.terminate() # p.kill() while p.poll() is None: # 當(dāng)子進(jìn)程未終止 line = p.stdout.readline().decode('gbk').strip() print(line) if p.returncode == 0: print('Subprogram success') else: print('Subprogram failed')
用 subprocess 模塊替換舊函數(shù)
在本節(jié)中,“a ==> b”表示a可以被b替代。
注意:如果找不到執(zhí)行的程序,則本節(jié)中的所有函數(shù)都會或多或少的調(diào)用失敗。此模塊引發(fā)OSError異常。
在以下示例中,我們假設(shè) subprocess 模塊使用 from subprocess import * 導(dǎo)入。
替換/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) sts = os.waitpid(p.pid, 0)
注意:
- 通常不需要通過shell調(diào)用程序。
- 查看returncode屬性比退出狀態(tài)更容易。
一個更實際的例子:
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示例:
pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") ==> pid = Popen(["/bin/mycmd", "myarg"]).pid
P_WAIT示例:
retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") ==> retcode = call(["/bin/mycmd", "myarg"])
Vector示例:
os.spawnvp(os.P_NOWAIT, path, args) ==> Popen([path] + args[1:])
Environment示例:
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)
替換popen2.*
注意:如果popen2函數(shù)的cmd參數(shù)是一個字符串,則該命令通過 /bin/sh 執(zhí)行。如果是列表,則直接執(zhí)行該命令。
(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) (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)
popen2.Popen3 和 popen3.Popen4 基本上用作subprocess.Popen,除了:
subprocess.Popen如果執(zhí)行失敗則引發(fā)異常。
capturestderr參數(shù)被替換為stderr參數(shù)。
必須指定stdin = PIPE和stdout = PIPE。
popen2默認(rèn)關(guān)閉所有文件描述符,但必須使用subprocess.Popen指定close_fds = True。
到此這篇關(guān)于Python中subprocess模塊的用法詳解的文章就介紹到這了,更多相關(guān)Python中subprocess模塊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
django實現(xiàn)登錄時候輸入密碼錯誤5次鎖定用戶十分鐘
這篇文章主要介紹了django實現(xiàn)登錄時候輸入密碼錯誤5次鎖定用戶十分鐘,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11Django查找網(wǎng)站項目根目錄和對正則表達(dá)式的支持
這篇文章主要介紹了Django查找網(wǎng)站項目根目錄和對正則表達(dá)式的支持,僅供參考,需要的朋友可以參考下2015-07-07python 實現(xiàn)12bit灰度圖像映射到8bit顯示的方法
這篇文章主要介紹了python 實現(xiàn)12bit灰度圖像映射到8bit顯示的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Python聊天室?guī)Ы缑鎸崿F(xiàn)的示例代碼(tkinter,Mysql,Treading,socket)
這篇文章主要介紹了Python聊天室?guī)Ы缑鎸崿F(xiàn)的示例代碼(tkinter,Mysql,Treading,socket),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04