Python之路(第二十篇) subprocess模块
subprocess英文意思:子進(jìn)程
那什么是進(jìn)程呢?
(一)關(guān)于進(jìn)程的相關(guān)理論基礎(chǔ)知識(shí)
進(jìn)程是對(duì)正在運(yùn)行程序的一個(gè)抽象,進(jìn)程的概念起源于操作系統(tǒng),是操作系統(tǒng)最核心的概念,操作系統(tǒng)的其他所有內(nèi)容都是圍繞進(jìn)程的概念展開(kāi)的。
所以想要真正了解進(jìn)程,必須事先了解操作系統(tǒng).
?
程序員無(wú)法把所有的硬件操作細(xì)節(jié)都了解到,管理這些硬件并且加以優(yōu)化使用是非常繁瑣的工作,這個(gè)繁瑣的工作就是操作系統(tǒng)來(lái)干的,有了他,程序員就從這些繁瑣的工作中解脫了出來(lái),只需要考慮自己的應(yīng)用軟件的編寫就可以了,應(yīng)用軟件直接使用操作系統(tǒng)提供的功能來(lái)間接使用硬件。
?
精簡(jiǎn)的說(shuō)的話,操作系統(tǒng)就是一個(gè)協(xié)調(diào)、管理和控制計(jì)算機(jī)硬件資源和軟件資源的控制程序。
?
?
?
操作系統(tǒng)所處的位置細(xì)說(shuō)的話,操作系統(tǒng)應(yīng)該分成兩部分功能:
?
-
隱藏了丑陋的硬件調(diào)用接口,為應(yīng)用程序員提供調(diào)用硬件資源的更好,更簡(jiǎn)單,更清晰的模型(系統(tǒng)調(diào)用接口)。應(yīng)用程序員有了這些接口后,就不用再考慮操作硬件的細(xì)節(jié),專心開(kāi)發(fā)自己的應(yīng)用程序即可。例如:操作系統(tǒng)提供了文件這個(gè)抽象概念,對(duì)文件的操作就是對(duì)磁盤的操作,有了文件我們無(wú)需再去考慮關(guān)于磁盤的讀寫控制(比如控制磁盤轉(zhuǎn)動(dòng),移動(dòng)磁頭讀寫數(shù)據(jù)等細(xì)節(jié)).
?
-
將應(yīng)用程序?qū)τ布Y源的競(jìng)態(tài)請(qǐng)求變得有序化例如:很多應(yīng)用軟件其實(shí)是共享一套計(jì)算機(jī)硬件,比方說(shuō)有可能有三個(gè)應(yīng)用程序同時(shí)需要申請(qǐng)打印機(jī)來(lái)輸出內(nèi)容,那么a程序競(jìng)爭(zhēng)到了打印機(jī)資源就打印,然后可能是b競(jìng)爭(zhēng)到打印機(jī)資源,也可能是c,這就導(dǎo)致了無(wú)序,打印機(jī)可能打印一段a的內(nèi)容然后又去打印c...,操作系統(tǒng)的一個(gè)功能就是將這種無(wú)序變得有序。
?
進(jìn)程是操作系統(tǒng)提供的最古老也是最重要的抽象概念之一。
?
什么是進(jìn)程
進(jìn)程(Process)是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。在早期面向進(jìn)程設(shè)計(jì)的計(jì)算機(jī)結(jié)構(gòu)中,進(jìn)程是程序的基本執(zhí)行實(shí)體;在當(dāng)代面向線程設(shè)計(jì)的計(jì)算機(jī)結(jié)構(gòu)中,進(jìn)程是線程的容器。程序是指令、數(shù)據(jù)及其組織形式的描述,進(jìn)程是程序的實(shí)體。
狹義定義:進(jìn)程是正在運(yùn)行的程序的實(shí)例(an instance of a computer program that is being executed)。
廣義定義:進(jìn)程是一個(gè)具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合的一次運(yùn)行活動(dòng)。它是操作系統(tǒng)動(dòng)態(tài)執(zhí)行的基本單元,在傳統(tǒng)的操作系統(tǒng)中,進(jìn)程既是基本的分配單元,也是基本的執(zhí)行單元。
?
簡(jiǎn)單的來(lái)說(shuō)就是程序僅僅只是一堆代碼而已,而進(jìn)程指的是程序的運(yùn)行過(guò)程,就是執(zhí)行一個(gè)一系列程序代碼的過(guò)程。
?
進(jìn)程和程序的區(qū)別
-
-
程序可以作為一種軟件資料長(zhǎng)期存在,而進(jìn)程是有一定生命期的。
-
程序是永久的,進(jìn)程是暫時(shí)的。
?
(二)進(jìn)程、父進(jìn)程、子進(jìn)程
父進(jìn)程:如果進(jìn)程a創(chuàng)建了進(jìn)程b,那么進(jìn)程a就是進(jìn)程b的父進(jìn)程,反之進(jìn)程b就是進(jìn)程a的子進(jìn)程。
?
父進(jìn)程定義在計(jì)算機(jī)領(lǐng)域,父進(jìn)程(Parent Process)指已創(chuàng)建一個(gè)或多個(gè)子進(jìn)程的進(jìn)程。
父進(jìn)程和子進(jìn)程的關(guān)系是管理和被管理的關(guān)系,當(dāng)父進(jìn)程終止時(shí),子進(jìn)程也隨之而終止。但子進(jìn)程終止,父進(jìn)程并不一定終止。
進(jìn)程得到的是除了代碼段是與父進(jìn)程共享的意外,其他所有的都是得到父進(jìn)程的一個(gè)副本,子進(jìn)程的所有資源都繼承父進(jìn)程,得到父進(jìn)程資源的副本,既然為副本,也就是說(shuō),二者并不共享地址空間。,兩個(gè)是單獨(dú)的進(jìn)程,繼承了以后二者就沒(méi)有什么關(guān)聯(lián)了,子進(jìn)程單獨(dú)運(yùn)行。
?
?
(三)subprocess模塊
任何操作系統(tǒng)上都可以通過(guò)命令行指令與操作系統(tǒng)進(jìn)行交互,比如Linux平臺(tái)下的shell、Windows下的cmd命令行。
Python來(lái)完成這些命令行指令的執(zhí)行呢?另外,我們應(yīng)該知道的是命令行指令的執(zhí)行通常有兩個(gè)我們比較關(guān)注的結(jié)果:
命令執(zhí)行的狀態(tài)碼--表示命令執(zhí)行是否成功
命令執(zhí)行的輸出結(jié)果--命令執(zhí)行成功后的輸出
?
?
早期的Python版本中,我們主要是通過(guò)os.system()、os.popen().read()等函數(shù)來(lái)執(zhí)行命令行指令的,另外還有一個(gè)很少使用的commands模塊。但是從Python 2.4開(kāi)始官方文檔中建議使用的是subprocess模塊。
?
subprocess是Python 2.4中新增的一個(gè)模塊,它允許你生成新的進(jìn)程,連接到它們的 input/output/error 管道,并獲取它們的返回(狀態(tài))碼。這個(gè)模塊的目的在于替換幾個(gè)舊的模塊和方法,如:
-
os.system
-
os.spawn*
?
?
1. subprocess模塊中的常用函數(shù)
| subprocess.run() | Python 3.5中新增的函數(shù)。執(zhí)行指定的命令,等待命令執(zhí)行完成后返回一個(gè)包含執(zhí)行結(jié)果的CompletedProcess類的實(shí)例。 |
| subprocess.call() | 執(zhí)行指定的命令,返回命令執(zhí)行狀態(tài),其功能類似于os.system(cmd)。 |
| subprocess.check_call() | Python 2.5中新增的函數(shù)。 執(zhí)行指定的命令,如果執(zhí)行成功則返回狀態(tài)碼,否則拋出異常。其功能等價(jià)于subprocess.run(..., check=True)。 |
| subprocess.check_output() | Python 2.7中新增的的函數(shù)。執(zhí)行指定的命令,如果執(zhí)行狀態(tài)碼為0則返回命令執(zhí)行結(jié)果,否則拋出異常。 |
| subprocess.getoutput(cmd) | 接收字符串格式的命令,執(zhí)行命令并返回執(zhí)行結(jié)果,其功能類似于os.popen(cmd).read()和commands.getoutput(cmd)。 |
| subprocess.getstatusoutput(cmd) | 執(zhí)行cmd命令,返回一個(gè)元組(命令執(zhí)行狀態(tài), 命令執(zhí)行結(jié)果輸出),其功能類似于commands.getstatusoutput()。 |
說(shuō)明:
在Python 3.5之后的版本中,官方文檔中提倡通過(guò)subprocess.run()函數(shù)替代其他函數(shù)來(lái)使用subproccess模塊的功能;
在Python 3.5之前的版本中,我們可以通過(guò)subprocess.call(),subprocess.getoutput()等上面列出的其他函數(shù)來(lái)使用subprocess模塊的功能;
subprocess.run()、subprocess.call()、subprocess.check_call()和subprocess.check_output()都是通過(guò)對(duì)subprocess.Popen的封裝來(lái)實(shí)現(xiàn)的高級(jí)函數(shù),因此如果我們需要更復(fù)雜功能時(shí),可以通過(guò)subprocess.Popen來(lái)完成。
subprocess.getoutput()和subprocess.getstatusoutput()函數(shù)是來(lái)自Python 2.x的commands模塊的兩個(gè)遺留函數(shù)。它們隱式的調(diào)用系統(tǒng)shell,并且不保證其他函數(shù)所具有的安全性和異常處理的一致性。另外,它們從Python 3.3.4開(kāi)始才支持Windows平臺(tái)。
?
?
?
2. 上面各函數(shù)的定義及參數(shù)說(shuō)明
函數(shù)參數(shù)列表:
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, universal_newlines=False)?subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)?subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)?subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)?subprocess.getstatusoutput(cmd)?subprocess.getoutput(cmd)
?
參數(shù)說(shuō)明:
-
args: 要執(zhí)行的shell命令,默認(rèn)應(yīng)該是一個(gè)字符串序列,該參數(shù)用于啟動(dòng)進(jìn)程。這可能是一個(gè)列表或一個(gè)字符串。如['df', '-Th']或('df', '-Th')【“'df -Th”這里是linux命令,在終端里輸入的,功能是顯示磁盤分區(qū)相關(guān)信息】,也可以是一個(gè)字符串,如'df -Th',但是此時(shí)需要把shell參數(shù)的值置為True。
-
shell: 如果shell為True,那么指定的命令將通過(guò)shell執(zhí)行。如果我們需要訪問(wèn)某些shell的特性,如管道、文件名通配符、環(huán)境變量擴(kuò)展功能,這將是非常有用的。當(dāng)然,python本身也提供了許多類似shell的特性的實(shí)現(xiàn),如glob、fnmatch、os.walk()、os.path.expandvars()、os.expanduser()和shutil等。當(dāng)shell=True時(shí),表示在系統(tǒng)默認(rèn)的shell環(huán)境中執(zhí)行新的進(jìn)程,此shell在windows表示為cmd.exe,在linux為/bin/sh。shell=True如果與不可信輸入結(jié)合使用,傳遞可能會(huì)帶來(lái)安全隱患。執(zhí)行輸入的命令最好不要設(shè)置為True,以防shell注入。
-
check: 如果check參數(shù)的值是True,且執(zhí)行命令的進(jìn)程以非0狀態(tài)碼退出,則會(huì)拋出一個(gè)CalledProcessError的異常,且該異常對(duì)象會(huì)包含 參數(shù)、退出狀態(tài)碼、以及stdout和stderr(如果它們有被捕獲的話)。
-
參數(shù)stdin, stdout, stderr分別表示程序的標(biāo)準(zhǔn)輸入、輸出、錯(cuò)誤句柄。他們可以是PIPE,文件描述符或文件對(duì)象,也可以設(shè)置為None,表示從父進(jìn)程繼承。PIPE表示創(chuàng)建管道。stderr特殊,可以設(shè)置成STDOUT,表示與標(biāo)準(zhǔn)輸出一致
-
run()函數(shù)默認(rèn)不會(huì)捕獲命令執(zhí)行結(jié)果的正常輸出和錯(cuò)誤輸出,如果我們向獲取這些內(nèi)容需要傳遞subprocess.PIPE,然后可以通過(guò)返回的CompletedProcess類實(shí)例的stdout和stderr屬性或捕獲相應(yīng)的內(nèi)容;
-
call()和check_call()函數(shù)返回的是命令執(zhí)行的狀態(tài)碼,而不是CompletedProcess類實(shí)例,所以對(duì)于它們而言,stdout和stderr不適合賦值為subprocess.PIPE;
-
check_output()函數(shù)默認(rèn)就會(huì)返回命令執(zhí)行結(jié)果,所以不用設(shè)置stdout的值,如果我們希望在結(jié)果中捕獲錯(cuò)誤信息,可以執(zhí)行stderr=subprocess.STDOUT。
-
input: 該參數(shù)是傳遞給Popen.communicate(),通常該參數(shù)的值必須是一個(gè)字節(jié)序列,如果universal_newlines=True,則其值應(yīng)該是一個(gè)字符串。
-
universal_newlines: 該參數(shù)影響的是輸入與輸出的數(shù)據(jù)格式,比如它的值默認(rèn)為False,此時(shí)stdout和stderr的輸出是字節(jié)序列;當(dāng)該參數(shù)的值設(shè)置為True時(shí),stdout和stderr的輸出是字符串。
?
args 所有調(diào)用的必填參數(shù),參數(shù)值為字符串、序列。處于方便,通常更偏向于提供序列。如果傳遞的是單一字符串,shell參數(shù)值必須為True,如果不提供其它任何參數(shù),傳遞單一字符串的情況下,該字符串必須是需要執(zhí)行的程序名。
?
?
subprocess.PIPE
subprocess.PIPE是特殊值,可用作標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出或標(biāo)準(zhǔn)錯(cuò)誤參數(shù),stdout 負(fù)責(zé)接收正常的輸出,stderr 負(fù)責(zé)接收錯(cuò)誤輸出,subprocess.PIPE 負(fù)責(zé)處理整體的數(shù)據(jù)流,把錯(cuò)誤信息通過(guò)管道賦值給變量stderr,把輸出信息通過(guò)管道賦值給stdout.
?
3、subprocess.run()
subprocess.run()函數(shù)是Python3.5中新增的一個(gè)高級(jí)函數(shù),功能是創(chuàng)建子進(jìn)程執(zhí)行某個(gè)命令,其返回值是一個(gè)subprocess.CompletedPorcess類的實(shí)例。
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False)
run()函數(shù)默認(rèn)不會(huì)捕獲命令執(zhí)行結(jié)果的正常輸出和錯(cuò)誤輸出,如果我們向獲取這些內(nèi)容需要傳遞subprocess.PIPE,然后可以通過(guò)返回的CompletedProcess類實(shí)例的stdout和stderr屬性或捕獲相應(yīng)的內(nèi)容。
?
subprocess.CompletedProcess類介紹
subprocess.CompletedProcess表示的是一個(gè)已結(jié)束進(jìn)程的狀態(tài)信息,它所包含的屬性如下:
-
args: 用于加載該進(jìn)程的參數(shù),這可能是一個(gè)列表或一個(gè)字符串
-
returncode: 子進(jìn)程的退出狀態(tài)碼。通常情況下,退出狀態(tài)碼為0則表示進(jìn)程成功運(yùn)行了;一個(gè)負(fù)值-N表示這個(gè)子進(jìn)程被信號(hào)N終止了
-
stdout: 從子進(jìn)程捕獲的stdout。這通常是一個(gè)字節(jié)序列,如果run()函數(shù)被調(diào)用時(shí)指定universal_newlines=True,則該屬性值是一個(gè)字符串。如果run()函數(shù)被調(diào)用時(shí)指定stderr=subprocess.STDOUT,那么stdout和stderr將會(huì)被整合到這一個(gè)屬性中,且stderr將會(huì)為None
-
stderr: 從子進(jìn)程捕獲的stderr。它的值與stdout一樣,是一個(gè)字節(jié)序列或一個(gè)字符串。如果stderr滅有被捕獲的話,它的值就為None
-
check_returncode(): 如果returncode是一個(gè)非0值,則該方法會(huì)拋出一個(gè)CalledProcessError異常。
?
subprocess.run()例子
?
例子1(測(cè)試環(huán)境 Windows7 )
import subprocess?v1 = subprocess.run(["ping","www.baidu.com"],stderr = subprocess.PIPE,stdout=subprocess.PIPE,universal_newlines=True)# 執(zhí)行ping命令,niversal_newlines為True時(shí),stdout將輸出字符串v2 = subprocess.run("calc",stderr = subprocess.PIPE,stdout=subprocess.PIPE) #打開(kāi)系統(tǒng)自帶的計(jì)算器print(v1.stdout)
輸出結(jié)果
?
正在 Ping www.a.shifen.com [119.75.213.61] 具有 32 字節(jié)的數(shù)據(jù):來(lái)自 119.75.213.61 的回復(fù): 字節(jié)=32 時(shí)間=44ms TTL=52來(lái)自 119.75.213.61 的回復(fù): 字節(jié)=32 時(shí)間=43ms TTL=52來(lái)自 119.75.213.61 的回復(fù): 字節(jié)=32 時(shí)間=43ms TTL=52來(lái)自 119.75.213.61 的回復(fù): 字節(jié)=32 時(shí)間=44ms TTL=52?119.75.213.61 的 Ping 統(tǒng)計(jì)信息:數(shù)據(jù)包: 已發(fā)送 = 4,已接收 = 4,丟失 = 0 (0% 丟失),往返行程的估計(jì)時(shí)間(以毫秒為單位):最短 = 43ms,最長(zhǎng) = 44ms,平均 = 43ms
??
?
?
例子2(測(cè)試環(huán)境 ubuntu16.04.1)
import subprocess?p = subprocess.run(["ls","-l"],stderr=subprocess.PIPE,stdout=subprocess.PIPE,universal_newlines=True)print(p.stdout)
輸出結(jié)果
?
?
?
?
?
4、subprocess.call()
subprocess.call運(yùn)行args描述的命令,等待命令完成后返回returncode屬性。subprocess.call返回的是命令執(zhí)行的狀態(tài)碼,而不是CompletedProcess類實(shí)例,所以對(duì)于它們而言,stdout和stderr不適合賦值subprocess.PIPE。
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
?
-
returncode: 子進(jìn)程的退出狀態(tài)碼。通常情況下,退出狀態(tài)碼為0則表示進(jìn)程成功運(yùn)行了;一個(gè)負(fù)值-N表示這個(gè)子進(jìn)程被信號(hào)N終止了。
?
subprocess.call()例子
例子1(測(cè)試環(huán)境 Windows7 )
import subprocessp = subprocess.call(["calc"])print(p)
輸出結(jié)果
0
?
?
例子2(測(cè)試環(huán)境 ubuntu16.04.1)
?
import subprocess?p = subprocess.call("ls -l",shell=True)print("----------------------")print(p)
?
輸出結(jié)果
總用量 16drwxrwxr-x 3 nicholas nicholas 4096 5月 23 00:23 b-rw-rw-r-- 1 nicholas nicholas 0 5月 8 19:03 __init__.py-rwxrw-r-- 1 nicholas nicholas 16 5月 22 21:58 old_test.txtdrwxrwxr-x 3 nicholas nicholas 4096 5月 23 00:23 temp-rw-rw-r-- 1 nicholas nicholas 100 5月 30 20:02 test.py----------------------0
?
?
?
?
5、subprocess.Popen介紹
subprocess.Popen類用于在一個(gè)新的進(jìn)程中執(zhí)行一個(gè)子程序,用來(lái)創(chuàng)建子進(jìn)程。
上面的subprocess.run()、subprocess.call()等介紹的這些函數(shù)都是基于subprocess.Popen類實(shí)現(xiàn)的,通過(guò)使用這些被封裝后的高級(jí)函數(shù)可以很方面的完成一些常見(jiàn)的需求。由于subprocess模塊底層的進(jìn)程創(chuàng)建和管理是由Popen類來(lái)處理的。
(1)subprocess.Popen的構(gòu)造函數(shù)
class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False,startup_info=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=())
?
參數(shù)說(shuō)明:
-
args: 要執(zhí)行的shell命令,可以是字符串,也可以是命令各個(gè)參數(shù)組成的序列。當(dāng)該參數(shù)的值是一個(gè)字符串時(shí),該命令的解釋過(guò)程是與平臺(tái)相關(guān)的,因此通常建議將args參數(shù)作為一個(gè)序列傳遞。
-
bufsize: 指定緩存策略,0表示不緩沖,1表示行緩沖,其他大于1的數(shù)字表示緩沖區(qū)大小,負(fù)數(shù) 表示使用系統(tǒng)默認(rèn)緩沖策略。
-
stdin, stdout, stderr: 分別表示程序標(biāo)準(zhǔn)輸入、輸出、錯(cuò)誤句柄。合法值為PIPE,DEVNULL,已存在文件描述符(一個(gè)正整數(shù)),已存在文件對(duì)象和None。 PIPE表示應(yīng)該創(chuàng)建通往子進(jìn)程的管道。DEVNULL表示應(yīng)該使用指定文件os.devnull。默認(rèn)參數(shù)None則表示無(wú)進(jìn)行重定向,子進(jìn)程文件句柄從父進(jìn)程繼承。此外,stderr還可以是STDOUT,表明子進(jìn)程的錯(cuò)誤數(shù)據(jù)應(yīng)該被放進(jìn)相同的文件句柄stdout。
-
preexec_fn: 用于指定一個(gè)將在子進(jìn)程運(yùn)行之前被調(diào)用的可執(zhí)行對(duì)象,只在Unix平臺(tái)下有效。
-
close_fds: 如果該參數(shù)的值為True,則除了0,1和2之外的所有文件描述符都將會(huì)在子進(jìn)程執(zhí)行之前被關(guān)閉。
默認(rèn)值根據(jù)平臺(tái)而異。Unix平臺(tái)總是默認(rèn)為True。在windows平臺(tái)下,如果close_fds被設(shè)置為True,則新創(chuàng)建的子進(jìn)程將不會(huì)繼承父進(jìn)程的輸入、輸出、錯(cuò)誤管道。(標(biāo)準(zhǔn)的輸入,輸出和錯(cuò)誤輸出分別表示為STDIN,STDOUT,STDERR,也可以用0,1,2來(lái)表示。)
-
shell: 該參數(shù)用于標(biāo)識(shí)是否使用shell作為要執(zhí)行的程序,如果shell值為True,則建議將args參數(shù)作為一個(gè)字符串傳遞而不要作為一個(gè)序列傳遞。為True時(shí),表示將通過(guò)shell來(lái)執(zhí)行。
-
cwd: 如果該參數(shù)值不是None,則該函數(shù)將會(huì)在執(zhí)行這個(gè)子進(jìn)程之前改變當(dāng)前工作目錄到cwd。
-
env: 用于指定子進(jìn)程的環(huán)境變量,如果env=None,那么子進(jìn)程的環(huán)境變量將從父進(jìn)程中繼承。如果env!=None,它的值必須是一個(gè)映射對(duì)象。
-
universal_newlines: 如果該參數(shù)值為True,則該文件對(duì)象的stdin,stdout和stderr將會(huì)作為文本流被打開(kāi),否則他們將會(huì)被作為二進(jìn)制流被打開(kāi)。
-
startupinfo和creationflags: 這兩個(gè)參數(shù)只在Windows下有效,它們將被傳遞給底層的CreateProcess()函數(shù),用于設(shè)置子進(jìn)程的一些屬性,如主窗口的外觀,進(jìn)程優(yōu)先級(jí)等。
?
(2) subprocess.Popen類的實(shí)例可調(diào)用的方法
| Popen.poll() | 用于檢查子進(jìn)程(命令)是否已經(jīng)執(zhí)行結(jié)束,沒(méi)結(jié)束返回None,結(jié)束后返回狀態(tài)碼。 |
| Popen.wait(timeout=None) | 等待子進(jìn)程結(jié)束,并返回狀態(tài)碼;如果在timeout指定的秒數(shù)之后進(jìn)程還沒(méi)有結(jié)束,將會(huì)拋出一個(gè)TimeoutExpired異常。 |
| Popen.communicate(input=None, timeout=None) | 該方法可用來(lái)與進(jìn)程進(jìn)行交互,比如發(fā)送數(shù)據(jù)到stdin,從stdout和stderr讀取數(shù)據(jù),直到到達(dá)文件末尾。 |
| Popen.send_signal(signal) | 發(fā)送指定的信號(hào)給這個(gè)子進(jìn)程。 |
| Popen.terminate() | 停止該子進(jìn)程。 |
| Popen.kill() | 殺死該子進(jìn)程。 |
?
關(guān)于communicate()方法的說(shuō)明:
-
該方法中的可選參數(shù) input 應(yīng)該是將被發(fā)送給子進(jìn)程的數(shù)據(jù),或者如沒(méi)有數(shù)據(jù)發(fā)送給子進(jìn)程,該參數(shù)應(yīng)該是None。input參數(shù)的數(shù)據(jù)類型必須是字節(jié)串,如果universal_newlines參數(shù)值為True,則input參數(shù)的數(shù)據(jù)類型必須是字符串。
-
該方法返回一個(gè)元組(stdout_data, stderr_data),這些數(shù)據(jù)將會(huì)是字節(jié)穿或字符串(如果universal_newlines的值為True)。
-
如果在timeout指定的秒數(shù)后該進(jìn)程還沒(méi)有結(jié)束,將會(huì)拋出一個(gè)TimeoutExpired異常。捕獲這個(gè)異常,然后重新嘗試通信不會(huì)丟失任何輸出的數(shù)據(jù)。但是超時(shí)之后子進(jìn)程并沒(méi)有被殺死,為了合理的清除相應(yīng)的內(nèi)容,一個(gè)好的應(yīng)用應(yīng)該手動(dòng)殺死這個(gè)子進(jìn)程來(lái)結(jié)束通信。
-
需要注意的是,這里讀取的數(shù)據(jù)是緩沖在內(nèi)存中的,所以,如果數(shù)據(jù)大小非常大或者是無(wú)限的,就不應(yīng)該使用這個(gè)方法。
?
例子1(測(cè)試環(huán)境 ubuntu16.04.1)
import subprocess?# 創(chuàng)建子進(jìn)程,執(zhí)行“l(fā)s -l”,查看當(dāng)前目錄的文件具體信息p = subprocess.Popen("ls -l",stdout=subprocess.PIPE,shell=True,universal_newlines=True)#p是Popen的一個(gè)實(shí)例對(duì)象 print(p.stdout.read()) #調(diào)用Popen的stdout,read()方法讀取輸出結(jié)果?# 修改執(zhí)行的目錄到/temp,然后再創(chuàng)建子進(jìn)程,執(zhí)行“l(fā)s -l”,查看當(dāng)前目錄文件的具體信息p1 = subprocess.Popen("ls -l",stdout=subprocess.PIPE,shell=True,universal_newlines=True,cwd='/tmp')print(p1.stdout.read())
?
輸出結(jié)果
?
?
?
?
例子2(測(cè)試環(huán)境 ubuntu16.04.1)
import subprocess?p = subprocess.Popen(["python3"],shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,universal_newlines=True) #實(shí)例化suprocess.Popen類創(chuàng)建子進(jìn)程p對(duì)象p.stdin.write("print('nicholas 1') \n")p.stdin.write("print('hello 2') \n")p.stdin.write("print('hworld 3') \n")out,err = p.communicate()print(out)
輸出結(jié)果
nicholas 1hello 2hworld 3
?
分析執(zhí)行過(guò)程
?
1、實(shí)例化suprocess.Popen類創(chuàng)建子進(jìn)程P對(duì)象,調(diào)用shell終端,在終端里執(zhí)行"python3"命令,終端進(jìn)入python環(huán)境,
2、向子進(jìn)程輸入"print('nicholas 1') \n"語(yǔ)句,向子進(jìn)程輸入"print('hello 2') \n"語(yǔ)句,向子進(jìn)程輸入"print('hworld 3') \n"語(yǔ)句
3、通過(guò)調(diào)用對(duì)象p的communicate()方法,獲取子進(jìn)程的輸出、錯(cuò)誤
4、打印子進(jìn)程的輸出
5、注意參數(shù)universal_newlines是True時(shí),stdin.write要傳入字符串,參數(shù)是False時(shí)要傳入bytes類型。
?
例子3(測(cè)試環(huán)境 Windows7 )
import subprocess?p = subprocess.Popen(["python"],shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,universal_newlines=True)out,err = p.communicate(input="print('nicholas niubi')")print(out)
輸出結(jié)果
nicholas niubi
?
?
分析:
1、實(shí)例化suprocess.Popen類創(chuàng)建子進(jìn)程p對(duì)象,打開(kāi)Windows命令行,執(zhí)行“python”命令,進(jìn)入python環(huán)境
2、通過(guò)調(diào)用對(duì)象p的communicate()方法向stdin發(fā)送數(shù)據(jù)"print('nicholas niubi')",并分別獲取對(duì)象p的輸出和錯(cuò)誤
3、打印輸出
4、注意參數(shù)universal_newlines是True時(shí),input要傳入字符串,參數(shù)是False時(shí)要傳入bytes類型。
?
?
?
?
參考資料
[1]https://www.cnblogs.com/Eva-J/articles/8253521.html
[2]https://www.cnblogs.com/Eva-J/articles/8253549.html
[3]https://www.cnblogs.com/yyds/p/7288916.html
轉(zhuǎn)載于:https://www.cnblogs.com/Nicholas0707/p/9114601.html
總結(jié)
以上是生活随笔為你收集整理的Python之路(第二十篇) subprocess模块的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 撞出租车误工费保险公司赔吗
- 下一篇: 当两年义务兵退伍后到派出所干特警工资多少