Python中subprocess模塊的用法詳解
Python subprocess模塊
subprocess是用于啟動(dòng)進(jìn)程,并與進(jìn)程通信的模塊。
格式
該模塊定義了一個(gè)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序列或字符串中的第一項(xiàng),但可以使用
executable參數(shù)顯式設(shè)置。
在UNIX 上,當(dāng) shell=False(默認(rèn)), 類Popen 用 os.execvp() 來執(zhí)行子程序,args通常應(yīng)該是一個(gè)序列,如果args是一個(gè)字符串,它也會(huì)被視為只有一個(gè)元素的序列。
在UNIX 上,當(dāng) shell=True,如果 args 是字符串,它將作為命令行字符串通過shell 執(zhí)行;如果是一個(gè)序列,它的第一項(xiàng)將作為命令行字符串,其他項(xiàng)將被視為附加的shell參數(shù)。
在 Windows 上,類Popen 用 CreateProcess() 來執(zhí)行子程序,它以字符串作為參數(shù)。
如果args是一個(gè)序列,它將使用 list2cmdline 方法轉(zhuǎn)換為字符串。需要注意的是,并非所有MS Windows應(yīng)用程序都以相同的方式解釋命令行,list2cmdline 是為使用與MS C運(yùn)行規(guī)則相同的應(yīng)用程序而設(shè)計(jì)的。
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)錯(cuò)誤輸出的文件句柄。
有效值為PIPE、現(xiàn)有文件描述符(正整數(shù))、現(xiàn)有文件對(duì)象和None。若賦值為PIPE ,就會(huì)為子程序創(chuàng)建新管道 ;若為None,不會(huì)發(fā)生重定向,子程序的文件句柄將從父程序繼承。
另外,stderr可以是STDOUT,這表明子程序的錯(cuò)誤數(shù)據(jù)可以被獲得并發(fā)送到stdout輸出。
preexec_fn 如果preexec_fn設(shè)置為可調(diào)用對(duì)象,則在執(zhí)行子進(jìn)程之前,將在子進(jìn)程中調(diào)用此對(duì)象。
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 文件對(duì)象stdout和stderr作為文本文件打開,但可以通過 '\n' (Unix), '\r' (Mac), '\r\n' (Win)斷行。所有這些外部表示都被Python程序視為'\n'。注意:僅當(dāng)Python使用通用換行支持(默認(rèn))構(gòu)建時(shí),此功能才可用。注意這些特征只在python支持通用換行的時(shí)候有效(默認(rèn)支持)。
此外,communication() 方法不會(huì)更新文件對(duì)象stdout,stdin和stderr的換行屬性。
startupinfo, creationflags 如果給定,將傳遞給底層的 CreateProcess() 函數(shù)。它可以指定主窗口的外觀和新進(jìn)程的優(yōu)先級(jí)等內(nèi)容。(僅限Windows)
該模塊還定義了兩個(gè)快捷功能:
call(*args, **kwargs):
使用參數(shù)運(yùn)行命令。等待命令完成,然后返回returncode屬性。
參數(shù)與Popen構(gòu)造函數(shù)相同。例:
retcode = call(["ls", "-l"])
異常
在新程序開始執(zhí)行之前,子進(jìn)程中引發(fā)的異常將在父進(jìn)程中重新引發(fā)。此外,異常對(duì)象將有一個(gè)名為'child_traceback'的額外屬性,該屬性是一個(gè)包含來自子進(jìn)程視點(diǎn)的回溯信息的字符串。
引發(fā)的最常見異常是OSError。例如,在嘗試執(zhí)行不存在的文件時(shí)會(huì)發(fā)生這種情況。應(yīng)用程序應(yīng)當(dāng)對(duì)OSErrors作出處理。
如果使用無效參數(shù)調(diào)用Popen,則會(huì)引發(fā)ValueError。
安全性
與其他一些 popen 函數(shù)不同,此實(shí)現(xiàn)永遠(yuǎn)不會(huì)隱式調(diào)用/bin/sh。
這意味著所有字符(包括shell元字符)都可以安全地傳遞給子進(jìn)程。
Popen 對(duì)象
Popen類的實(shí)例具有以下方法:
Popen.poll():
檢查子進(jìn)程是否已終止。終止則返回returncode屬性;否則,返回None。
Popen.wait(timeout=None):
等待子進(jìn)程終止,返回returncode屬性。
如果進(jìn)程在超時(shí)秒后沒有終止,則引發(fā) TimeoutExpired 異常。捕獲此異常并重試等待將會(huì)更安全。
注意:當(dāng)使用stdout = PIPE或stderr = PIPE,并且子進(jìn)程生成太多輸出以致于阻止了等待OS管道緩沖區(qū)接受更多數(shù)據(jù)時(shí),將導(dǎo)致死鎖。使用管道時(shí)可以使用 Popen.communicate() 來避免這種情況。
注意:該功能使用忙循環(huán)(非阻塞呼叫和短暫睡眠)實(shí)現(xiàn)。
在Python3.3中添加了timeout參數(shù)。
從Python3.4開始不推薦使用endtime參數(shù)。這是無意中暴露在3.3中,但沒有記錄,因?yàn)樗撬饺藘?nèi)部使用。請(qǐng)改用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()返回一個(gè) tuple(stdout_data, stderr_data) 。如果在文本模式下打開流,則數(shù)據(jù)將是字符串;否則,是字節(jié)。
注意:如果要將數(shù)據(jù)發(fā)送到進(jìn)程的stdin,則需要使用stdin = PIPE創(chuàng)建Popen對(duì)象。同樣,要在結(jié)果元組(tuple)中獲取除None之外的任何內(nèi)容,還需要設(shè)置stdout = PIPE and/or stderr = PIPE。
如果進(jìn)程在超時(shí)(timeout)秒后沒有終止,則會(huì)引發(fā)TimeoutExpired異常。捕獲此異常并重試通信不會(huì)丟失任何輸出。
如果超時(shí)到期,則子進(jìn)程不會(huì)被終止,因此為了正確清理,行為良好的應(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ù)大小很大或不受限制,請(qǐng)不要使用此方法。
在Python3.3中添加了timeout參數(shù)。
Popen.send_signal(signal):
向子進(jìn)程發(fā)送signal信號(hào)。
注意:在 Windows 上,SIGTERM和terminate() 的作用相同??梢詫?CTRL_C_EVENT 和 CTRL_BREAK_EVENT 發(fā)送到使用 creationflags 參數(shù)啟動(dòng)的進(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ù)序列或單個(gè)字符串。
Python3.3中的新功能。
Popen.stdin:
如果stdin參數(shù)是PIPE,則此屬性是open() 返回的可寫流對(duì)象。如果指定了encoding或errors參數(shù)或者universal_newlines參數(shù)為True,則流是文本流,否則它是字節(jié)流。如果stdin參數(shù)不是PIPE,則此屬性為None。
obj.stdin.write(" args ")
Popen.stdout:
如果stdout參數(shù)是PIPE,則此屬性是open() 返回的可讀流對(duì)象。從流中讀取提供子進(jìn)程的輸出。如果指定了encoding或errors參數(shù)或者universal_newlines參數(shù)為True,則流是文本流,否則它是字節(jié)流。如果stdout參數(shù)不是PIPE,則此屬性為None。
obj.stdout.read()
Popen.stderr:
如果stderr參數(shù)是PIPE,則此屬性是open() 返回的可讀流對(duì)象。從流中讀取提供子進(jìn)程的錯(cuò)誤輸出。如果指定了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)程被信號(hào) 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信號(hào)*** # os.kill(p.pid, signal.CTRL_C_EVENT) # p.send_signal(signal.CTRL_C_EVENT) # ***SIGTERM信號(hào)*** # 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ù)都會(huì)或多或少的調(diào)用失敗。此模塊引發(fā)OSError異常。
在以下示例中,我們假設(shè) subprocess 模塊使用 from subprocess import * 導(dǎo)入。
替換/bin/sh shell反引號(hào)
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)更容易。
一個(gè)更實(shí)際的例子:
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ù)是一個(gè)字符串,則該命令通過 /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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- python調(diào)用subprocess模塊實(shí)現(xiàn)命令行操作控制SVN的方法
- 一文搞懂Python中subprocess模塊的使用
- python運(yùn)行shell命令subprocess的實(shí)現(xiàn)
- Python?subprocess.Popen?實(shí)時(shí)輸出?stdout的解決方法(正確管道寫法)
- 一文詳解Python中subprocess模塊的用法
- python?subprocess執(zhí)行外部命令常用方法詳細(xì)舉例
- python?subprocess.run()、subprocess.Popen()、subprocess.check_output()
相關(guān)文章
django實(shí)現(xiàn)登錄時(shí)候輸入密碼錯(cuò)誤5次鎖定用戶十分鐘
這篇文章主要介紹了django實(shí)現(xiàn)登錄時(shí)候輸入密碼錯(cuò)誤5次鎖定用戶十分鐘,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11Django查找網(wǎng)站項(xiàng)目根目錄和對(duì)正則表達(dá)式的支持
這篇文章主要介紹了Django查找網(wǎng)站項(xiàng)目根目錄和對(duì)正則表達(dá)式的支持,僅供參考,需要的朋友可以參考下2015-07-07python 實(shí)現(xiàn)12bit灰度圖像映射到8bit顯示的方法
這篇文章主要介紹了python 實(shí)現(xiàn)12bit灰度圖像映射到8bit顯示的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07python實(shí)現(xiàn)TCPserver的使用示例
python實(shí)現(xiàn)TCPserver是一件簡單的事情,只要通過socket這個(gè)模塊就可以實(shí)現(xiàn),本文就來介紹一下python實(shí)現(xiàn)TCPserver的使用示例,感興趣的可以了解一下2023-10-10Python聊天室?guī)Ы缑鎸?shí)現(xiàn)的示例代碼(tkinter,Mysql,Treading,socket)
這篇文章主要介紹了Python聊天室?guī)Ы缑鎸?shí)現(xiàn)的示例代碼(tkinter,Mysql,Treading,socket),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04