python中的subprocess.Popen()使用詳解
從python2.4版本開(kāi)始,可以用subprocess這個(gè)模塊來(lái)產(chǎn)生子進(jìn)程,并連接到子進(jìn)程的標(biāo)準(zhǔn)輸入/輸出/錯(cuò)誤中去,還可以得到子進(jìn)程的返回值。
subprocess意在替代其他幾個(gè)老的模塊或者函數(shù),比如:os.system os.spawn* os.popen* popen2.* commands.*
一、subprocess.Popen
subprocess模塊定義了一個(gè)類: Popen
class subprocess.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:
args參數(shù)??梢允且粋€(gè)字符串,可以是一個(gè)包含程序參數(shù)的列表。要執(zhí)行的程序一般就是這個(gè)列表的第一項(xiàng),或者是字符串本身。
subprocess.Popen(["cat","test.txt"]) subprocess.Popen("cat test.txt")
這兩個(gè)之中,后者將不會(huì)工作。因?yàn)槿绻且粋€(gè)字符串的話,必須是程序的路徑才可以。(考慮unix的api函數(shù)exec,接受的是字符串列表)但是下面的可以工作
subprocess.Popen("cat test.txt", shell=True)
這是因?yàn)樗喈?dāng)于
subprocess.Popen(["/bin/sh", "-c", "cat test.txt"])
在*nix下,當(dāng)shell=False(默認(rèn))時(shí),Popen使用os.execvp()來(lái)執(zhí)行子程序。args一般要是一個(gè)【列表】。如果args是個(gè)字符串的話,會(huì)被當(dāng)做是可執(zhí)行文件的路徑,這樣就不能傳入任何參數(shù)了。
注意:
shlex.split()可以被用于序列化復(fù)雜的命令參數(shù),比如:
>>> shlex.split('ls ps top grep pkill') ['ls', 'ps', 'top', 'grep', 'pkill'] >>>import shlex, subprocess >>>command_line = raw_input() /bin/cat -input test.txt -output "diege.txt" -cmd "echo '$MONEY'" >>>args = shlex.split(command_line) >>> print args ['/bin/cat', '-input', 'test.txt', '-output', 'diege.txt', '-cmd', "echo '$MONEY'"] >>>p=subprocess.Popen(args)
可以看到,空格分隔的選項(xiàng)(如-input)和參數(shù)(如test.txt)會(huì)被分割為列表里獨(dú)立的項(xiàng),但引號(hào)里的或者轉(zhuǎn)義過(guò)的空格不在此列。這也有點(diǎn)像大多數(shù)shell的行為。
在linux下,當(dāng)shell=True時(shí),如果arg是個(gè)字符串,就使用shell來(lái)解釋執(zhí)行這個(gè)字符串。如果args是個(gè)列表,則第一項(xiàng)被視為命令,其余的都視為是給shell本身的參數(shù)。也就是說(shuō),等效于:
subprocess.Popen(['/bin/sh', '-c', args[0], args[1], ...])
在Windows下,下面的卻又是可以工作的
subprocess.Popen(["notepad.exe", "test.txt"]) subprocess.Popen("notepad.exe test.txt")
這是由于windows下的api函數(shù)CreateProcess接受的是一個(gè)字符串。即使是列表形式的參數(shù),也需要先合并成字符串再傳遞給api函數(shù)
subprocess.Popen("notepad.exe test.txt" shell=True)
等同于
subprocess.Popen("cmd.exe /C "+"notepad.exe test.txt" shell=True)
bufsize參數(shù):
如果指定了bufsize參數(shù)作用就和內(nèi)建函數(shù)open()一樣:0表示不緩沖,1表示行緩沖,其他正數(shù)表示近似的緩沖區(qū)字節(jié)數(shù),負(fù)數(shù)表示使用系統(tǒng)默認(rèn)值。默認(rèn)是0。
executable參數(shù):
指定要執(zhí)行的程序。它很少會(huì)被用到:一般程序可以由args 參數(shù)指定。如果shell=True ,executable 可以用于指定用哪個(gè)shell來(lái)執(zhí)行(比如bash、csh、zsh等)。*nix下,默認(rèn)是 /bin/sh ,windows下,就是環(huán)境變量 COMSPEC 的值。windows下,只有當(dāng)你要執(zhí)行的命令確實(shí)是shell內(nèi)建命令(比如dir ,copy 等)時(shí),你才需要指定shell=True ,而當(dāng)你要執(zhí)行一個(gè)基于命令行的批處理腳本的時(shí)候,不需要指定此項(xiàng)。
stdin stdout和stderr:
stdin stdout和stderr,分別表示子程序的標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤??蛇x的值有PIPE或者一個(gè)有效的文件描述符(其實(shí)是個(gè)正整數(shù))或者一個(gè)文件對(duì)象,還有None。如果是PIPE,則表示需要?jiǎng)?chuàng)建一個(gè)新的管道,如果是None,不會(huì)做任何重定向工作,子進(jìn)程的文件描述符會(huì)繼承父進(jìn)程的。另外,stderr的值還可以是STDOUT,表示子進(jìn)程的標(biāo)準(zhǔn)錯(cuò)誤也輸出到標(biāo)準(zhǔn)輸出。
preexec_fn參數(shù):
如果把preexec_fn設(shè)置為一個(gè)可調(diào)用的對(duì)象(比如函數(shù)),就會(huì)在子進(jìn)程被執(zhí)行前被調(diào)用。(僅限*nix)
close_fds參數(shù):
如果把close_fds設(shè)置成True,*nix下會(huì)在開(kāi)子進(jìn)程前把除了0、1、2以外的文件描述符都先關(guān)閉。在 Windows下也不會(huì)繼承其他文件描述符。
shell參數(shù):
如果把shell設(shè)置成True,指定的命令會(huì)在shell里解釋執(zhí)行。
cwd參數(shù):
如果cwd不是None,則會(huì)把cwd做為子程序的當(dāng)前目錄。注意,并不會(huì)把該目錄做為可執(zhí)行文件的搜索目錄,所以不要把程序文件所在目錄設(shè)置為cwd 。
env參數(shù):
如果env不是None,則子程序的環(huán)境變量由env的值來(lái)設(shè)置,而不是默認(rèn)那樣繼承父進(jìn)程的環(huán)境變量。注意,即使你只在env里定義了某一個(gè)環(huán)境變量的值,也會(huì)阻止子程序得到其他的父進(jìn)程的環(huán)境變量(也就是說(shuō),如果env里只有1項(xiàng),那么子進(jìn)程的環(huán)境變量就只有1個(gè)了)。例如:
>>> subprocess.Popen('env', env={'test':'123', 'testtext':'zzz'}) test=123 <subprocess.Popen object at 0x2870ad2c> testtext=zzz
universal_newlines參數(shù):
如果把universal_newlines 設(shè)置成True,則子進(jìn)程的stdout和stderr被視為文本對(duì)象,并且不管是*nix的行結(jié)束符('/n'),還是老mac格式的行結(jié)束符('/r' ),還是windows 格式的行結(jié)束符('/r/n' )都將被視為 '/n' 。
startupinfo和creationflags參數(shù):
如果指定了startupinfo和creationflags,將會(huì)被傳遞給后面的CreateProcess()函數(shù),用于指定子程序的各種其他屬性,比如主窗口樣式或者是子進(jìn)程的優(yōu)先級(jí)等。(僅限Windows)
二、subprocess.PIPE
subprocess.PIPE
一個(gè)可以被用于Popen的stdin 、stdout 和stderr 3個(gè)參數(shù)的特輸值,表示需要?jiǎng)?chuàng)建一個(gè)新的管道。
subprocess.STDOUT
一個(gè)可以被用于Popen的stderr參數(shù)的輸出值,表示子程序的標(biāo)準(zhǔn)錯(cuò)誤匯合到標(biāo)準(zhǔn)輸出。
實(shí)例:
>>>p=subprocess.Popen("df -h",shell=True,stdout=subprocess.PIPE) >>>out=p.stdout.readlines() >>>out [b'Filesystem Size Used Avail Capacity Mounted on\n', b'/dev/ad0s1a 713M 313M 343M 48% /\n', b'devfs 1.0K 1.0K 0B 100% /dev\n', b'/dev/ad0s1e 514M 2.1M 471M 0% /tmp\n', b'/dev/ad0s1f 4.3G 2.5G 1.4G 64% /usr\n', b'/dev/ad0s1d 2.0G 121M 1.7G 6% /var\n' >>> for line in out: ... print line.strip() ... Filesystem Size Used Avail Capacity Mounted on /dev/ad0s1a 713M 313M 343M 48% / devfs 1.0K 1.0K 0B 100% /dev /dev/ad0s1e 514M 2.1M 471M 0% /tmp /dev/ad0s1f 4.3G 2.5G 1.4G 64% /usr /dev/ad0s1d 2.0G 121M 1.7G 6% /var
stdout可以使用read(),readline(),readlines()等方法
三、方便的函數(shù)
1、subprocess.call
subprocess.call (*popenargs , **kwargs )
執(zhí)行命令,并等待命令結(jié)束,再返回子進(jìn)程的返回值。參數(shù)同Popen,查看/usr/lib/python2.7/subprocess.py
去掉文檔,其實(shí)是這樣的:
def call(*popenargs, **kwargs): return Popen(*popenargs, **kwargs).wait() >>> subprocess.call('ifconfig',shell=True)
2、subprocess.check_call
subprocess.check_call (*popenargs , **kwargs )
執(zhí)行上面的call命令,并檢查返回值,如果子進(jìn)程返回非0,則會(huì)拋出CalledProcessError異常,這個(gè)異常會(huì)有個(gè)returncode
屬性,記錄子進(jìn)程的返回值。
def check_call(*popenargs, **kwargs): retcode = call(*popenargs, **kwargs) if retcode: cmd = kwargs.get("args") raise CalledProcessError(retcode, cmd) return 0 >>> subprocess.check_call('ifconfig') >>> subprocess.call('noifconfig') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.7/subprocess.py", line 493, in call return Popen(*popenargs, **kwargs).wait() File "/usr/local/lib/python2.7/subprocess.py", line 679, in __init__ errread, errwrite) File "/usr/local/lib/python2.7/subprocess.py", line 1228, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory
異常子進(jìn)程里拋出的異常,會(huì)在父進(jìn)程中再次拋出。并且,異常會(huì)有個(gè)叫child_traceback的額外屬性,這是個(gè)包含子進(jìn)程錯(cuò)誤traceback信息的字符串。遇到最多的錯(cuò)誤回是 OSError,比如執(zhí)行了一個(gè)并不存在的子程序就會(huì)產(chǎn)生OSError。另外,如果使用錯(cuò)誤的參數(shù)調(diào)用Popen,會(huì)拋出ValueError。當(dāng)子程序返回非0時(shí),check_call()還會(huì)產(chǎn)生CalledProcessError 異常。
安全性不像其他的popen函數(shù),本函數(shù)不會(huì)調(diào)用/bin/sh來(lái)解釋命令,也就是說(shuō),命令中的每一個(gè)字符都會(huì)被安全地傳遞到子進(jìn)程里。
3、check_output
check_output()執(zhí)行程序,并返回其標(biāo)準(zhǔn)輸出. def check_output(*popenargs, **kwargs): process = Popen(*popenargs, stdout=PIPE, **kwargs) output, unused_err = process.communicate() retcode = process.poll() if retcode: cmd = kwargs.get("args") raise CalledProcessError(retcode, cmd, output=output) return output p=subprocess.check_output('ifconfig')
結(jié)果是所有行/n分割的一個(gè)字符串可以直接print出來(lái) 這里開(kāi)始
4、Popen對(duì)象
產(chǎn)生對(duì)象
p=subprocess.Popen("df -h",shell=True,stdout=subprocess.PIPE) >>> dir(p)
Popen對(duì)象有以下方法:
Popen.poll()
檢查子進(jìn)程是否已結(jié)束,設(shè)置并返回returncode屬性。
>>> p.poll() 0 Popen.wait()
等待子進(jìn)程結(jié)束,設(shè)置并返回returncode屬性。
>>> p.wait() 0
注意: 如果子進(jìn)程輸出了大量數(shù)據(jù)到stdout或者stderr的管道,并達(dá)到了系統(tǒng)pipe的緩存大小的話,子進(jìn)程會(huì)等待父進(jìn)程讀取管道,而父進(jìn)程此時(shí)正wait著的話,將會(huì)產(chǎn)生傳說(shuō)中的死鎖,后果是非常嚴(yán)重滴。建議使用communicate() 來(lái)避免這種情況的發(fā)生。
Popen.communicate(input=None)
和子進(jìn)程交互:發(fā)送數(shù)據(jù)到stdin,并從stdout和stderr讀數(shù)據(jù),直到收到EOF。等待子進(jìn)程結(jié)束。可選的input如有有的話,要為字符串類型。
此函數(shù)返回一個(gè)元組: (stdoutdata , stderrdata ) 。
注意,要給子進(jìn)程的stdin發(fā)送數(shù)據(jù),則Popen的時(shí)候,stdin要為PIPE;同理,要可以接收數(shù)據(jù)的話,stdout或者stderr也要為PIPE。
p1=subprocess.Popen('cat /etc/passwd',shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE) >>> p2=subprocess.Popen('grep 0:0',shell=True,stdin=p1.stdout,stdout=subprocess.PIPE)
注意:讀到的數(shù)據(jù)會(huì)被緩存在內(nèi)存里,所以數(shù)據(jù)量非常大的時(shí)候要小心了。
>>> p.communicate() (b'Filesystem Size Used Avail Capacity Mounted on\n/dev/ad0s1a 713M 313M 343M 48% /\ndevfs 1.0K 1.0K 0B 100% /dev\n/dev/ad0s1e 514M 2.1M 471M 0% /tmp\n/dev/ad0s1f 4.3G 2.5G 1.4G 64% /usr\n/dev/ad0s1d 2.0G 121M 1.7G 6% /var\n', None) Popen.send_signal(signal)
給子進(jìn)程發(fā)送signal信號(hào)。
注意:windows下目前只支持發(fā)送SIGTERM,等效于下面的terminate() 。
Popen.terminate()
停止子進(jìn)程。Posix下是發(fā)送SIGTERM信號(hào)。windows下是調(diào)用TerminateProcess()這個(gè)API。
Popen.kill()
殺死子進(jìn)程。Posix下是發(fā)送SIGKILL信號(hào)。windows下和terminate() 無(wú)異。
Popen.stdin
如果stdin 參數(shù)是PIPE,此屬性就是一個(gè)文件對(duì)象,否則為None 。
Popen.stdout
如果stdout參數(shù)是PIPE,此屬性就是一個(gè)文件對(duì)象,否則為None 。
Popen.stderr
如果stderr 參數(shù)是PIPE,此屬性就是一個(gè)文件對(duì)象,否則為None 。
Popen.pid
子進(jìn)程的進(jìn)程號(hào)。注意,如果shell 參數(shù)為T(mén)rue,這屬性指的是子shell的進(jìn)程號(hào)。
>>> p.pid 22303 Popen.returncode
子程序的返回值,由poll()或者wait()設(shè)置,間接地也由communicate()設(shè)置。
如果為None,表示子進(jìn)程還沒(méi)終止。
如果為負(fù)數(shù)-N的話,表示子進(jìn)程被N號(hào)信號(hào)終止。(僅限*nux)
用subprocess來(lái)代替其他函數(shù)都可以用subprocess來(lái)完成,我們假定是用 “from subprocess import *” 來(lái)導(dǎo)入模塊的:
代替shell命令:
p=`ls -l`
等效于
p=Popen(['ls','-l'],stdout=PIPE).communicate()[0]
代替shell管道:
p=`dmesg | grep cpu`
等效于
p1=Popen(['dmesg'],stdout=PIPE) p2=Popen(['grep','cpu'],stdin=p1.stdout,stdout=PIPE) output = p2.communicate()[0] output cpu0: <ACPI CPU> on acpi0\nacpi_throttle0: <ACPI CPU Throttling> on cpu0\n >>> p1=subprocess.Popen('cat /etc/passwd',shell=True,stdout=subprocess.PIPE) >>> p2=subprocess.Popen('grep 0:0',shell=True,stdin=p1.stdout,stdout=subprocess.PIPE) >>> p3=subprocess.Popen("cut -d ':' -f 7",shell=True,stdin=p2.stdout,stdout=subprocess.PIPE) >>> print p3.stdout.read()
代替os.system()
lsl = os.system('ls '+'-l')
這個(gè)是一個(gè)返回狀態(tài)
等效于
p=Popen('ls -l', shell=True) lsl=os.waitpid(p.pid,0)[1]
注意:
通常并不需要用shell來(lái)調(diào)用程序。用subprocess可以更方便地得到子程序的返回值。
其實(shí),更真實(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"])
返回值處理:
pipe = os.popen(“cmd”, ‘w') ... rc = pipe.close() if rc != 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”
以上這篇python中的subprocess.Popen()使用詳解就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- python基礎(chǔ)教程之popen函數(shù)操作其它程序的輸入和輸出示例
- Python?subprocess.Popen?實(shí)時(shí)輸出?stdout的解決方法(正確管道寫(xiě)法)
- Python調(diào)用系統(tǒng)命令的四種方法詳解(os.system、os.popen、commands、subprocess)
- Python調(diào)用系統(tǒng)命令os.system()和os.popen()的實(shí)現(xiàn)
- 解決python3中os.popen()出錯(cuò)的問(wèn)題
- 對(duì)Python subprocess.Popen子進(jìn)程管道阻塞詳解
- Python中的Popen函數(shù)demo演示
相關(guān)文章
Python+PyQT5的子線程更新UI界面的實(shí)例
今天小編就為大家分享一篇Python+PyQT5的子線程更新UI界面的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-06-06Python Pygame實(shí)現(xiàn)兔子獵人守護(hù)城堡游戲
這篇文章主要介紹了用python來(lái)制作的一個(gè)守護(hù)類小游戲兔子獵人守護(hù)城堡,文中的示例代碼介紹得很詳細(xì),感興趣的小伙伴快來(lái)跟隨小編一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12python 實(shí)現(xiàn)圖片旋轉(zhuǎn) 上下左右 180度旋轉(zhuǎn)的示例
今天小編就為大家分享一篇python 實(shí)現(xiàn)圖片旋轉(zhuǎn) 上下左右 180度旋轉(zhuǎn)的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01在Python的struct模塊中進(jìn)行數(shù)據(jù)格式轉(zhuǎn)換的方法
這篇文章主要介紹了在Python的struct模塊中進(jìn)行數(shù)據(jù)格式轉(zhuǎn)換的方法,文中還給出了C語(yǔ)言和Python語(yǔ)言的數(shù)據(jù)類型比較,需要的朋友可以參考下2015-06-06如何以Winsows Service方式運(yùn)行JupyterLab
這篇文章主要介紹了如何以Winsows Service方式運(yùn)行JupyterLab的教程2020-08-08由淺入深學(xué)習(xí)TensorFlow MNIST 數(shù)據(jù)集
這篇文章主要由淺入深學(xué)習(xí)的講解TensorFlow MNIST 數(shù)據(jù)集,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09Opencv實(shí)現(xiàn)計(jì)算兩條直線或線段角度方法詳解
這篇文章主要介紹了Opencv實(shí)現(xiàn)計(jì)算兩條直線或線段角度方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-12-12Python小白學(xué)習(xí)爬蟲(chóng)常用請(qǐng)求報(bào)頭
在本篇文章里小編給大家整理了關(guān)于Python小白學(xué)習(xí)爬蟲(chóng)常用請(qǐng)求報(bào)頭的相關(guān)知識(shí)點(diǎn),需要的朋友們可以學(xué)習(xí)下。2020-06-06