python3中使用subprocess模块执行外部命令
一. subprocess模塊介紹
subprocess模塊可以替代os模塊下的os.system和os.popen等操作方法
subprocess模塊在python2和python3上的使用上有一定的區(qū)別,本文主要介紹的是在python3.6上的使用
subprocess模塊的作用是執(zhí)行外部命令(支持同步執(zhí)行和異步執(zhí)行),可以返回執(zhí)行狀態(tài)碼,也可以返回執(zhí)行內(nèi)容
subprocess模塊的方法有很多,最核心的方法為subprocess.Popen方法,python3中如果只需要同步執(zhí)行,優(yōu)先使用subprocess.run方法
二. subprocess.run()方法的介紹
2.1 執(zhí)行代碼:在windows下執(zhí)行一條cmd命令
# -*- coding:utf-8 -*- # Author:chinablueimport subprocess# 在windows下執(zhí)行cmd命令:echo hello dj p = subprocess.run("echo hello dj", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(f'獲取返回對(duì)象: {p}') print(f'獲取執(zhí)行命令:{p.args}') print(f'獲取返回碼:{p.returncode}') print(f'獲取返回?cái)?shù)據(jù):{p.stdout}')2.2 執(zhí)行結(jié)果:
獲取返回對(duì)象: CompletedProcess(args='echo hello dj', returncode=0, stdout=b'hello dj\r\n', stderr=b'') 獲取執(zhí)行命令:echo hello dj 獲取返回碼:0 獲取返回?cái)?shù)據(jù):b'hello dj\r\n'2.3 分析小結(jié):
1 ) subprocess.run()方法是一個(gè)同步方法,執(zhí)行后會(huì)返回一個(gè)CompletedProcess對(duì)象
2 ) 通過管道可以捕獲子進(jìn)程的標(biāo)準(zhǔn)輸出(stdout)和標(biāo)準(zhǔn)錯(cuò)誤(stderr)
如果使用的是python3.7及以上版本,可以使用capture_output=True參數(shù)替換stdout=subprocess.PIPE和stderr=subprocess.PIPE參數(shù)
p = subprocess.run("echo hello dj", shell=True, capture_output=True) print(f'獲取返回?cái)?shù)據(jù):{p.stdout}') # 執(zhí)行結(jié)果:獲取返回?cái)?shù)據(jù):b'hello dj\r\n'將執(zhí)行結(jié)果輸出到一個(gè)文件中去
# 將命令的執(zhí)行結(jié)果輸出到output.txt文件中 # 遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:778463939 # 尋找有志同道合的小伙伴,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! with open("output.txt", "w") as f:p1 = subprocess.run("dir", shell=True, stdout=f, universal_newlines=True, encoding="utf-8")3 ) 默認(rèn)情況下,獲取的返回?cái)?shù)據(jù)(stdxxx)為字節(jié)類型。
通過universal_newlines=True參數(shù)可以讓返回?cái)?shù)據(jù)以文本字符串輸出
p = subprocess.run("echo hello dj", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) print(f'獲取返回?cái)?shù)據(jù):{p.stdout}') # 運(yùn)行結(jié)果:獲取返回?cái)?shù)據(jù):hello dj如果使用的是python3.7及以上版本, 可以使用text=True參數(shù)替換universal_newlines=True參數(shù)
p = subprocess.run("echo hello dj", shell=True, capture_output=True, text=True) print(f'獲取返回?cái)?shù)據(jù):{p.stdout}') # 運(yùn)行結(jié)果:獲取返回?cái)?shù)據(jù):hello dj如果不使用universal_newlines=True參數(shù)或text=True參數(shù),我們也可以對(duì)p.stdout進(jìn)行解碼轉(zhuǎn)換
p = subprocess.run("echo hello dj", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(f'獲取返回?cái)?shù)據(jù):{p.stdout.decode("gbk")}') # 注意:windows下需要使用gbk解碼 # 運(yùn)行結(jié)果:獲取返回?cái)?shù)據(jù):hello dj4 ) 關(guān)于返回狀態(tài)碼的說明
如果命令執(zhí)行成功,returncode返回0; 如果命令執(zhí)行失敗,returncode返回負(fù)值
check=True參數(shù)會(huì)自動(dòng)檢查p.returncode是否返回0, 如果不是0就拋出subprocess.CalledProcessError異常
p = subprocess.run("echo1", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) print(f'獲取返回?cái)?shù)據(jù):{p.stdout}')如果不使用 check=True參數(shù),我們可以通過p.returncode來做判斷條件, 進(jìn)而打印出詳細(xì)錯(cuò)誤p.stderr
# 遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:778463939 # 尋找有志同道合的小伙伴,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! p = subprocess.run("echo1", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) if p.returncode !=0:print(f'命令執(zhí)行失敗:{p.stderr}')三. subprocess.Popen()方法的介紹
subprocess.run()是通過subprocess.Popen()來實(shí)現(xiàn)的
subprocess.Popen()可以異步執(zhí)行
3.1 執(zhí)行代碼:在windows下執(zhí)行一條cmd命令
# -*- coding:utf-8 -*- # 遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:778463939 # 尋找有志同道合的小伙伴,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書!import subprocess# 在windows下執(zhí)行cmd命令:echo chinablue p = subprocess.Popen("echo chinablue", shell=True,stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) print(f"獲取返回對(duì)象: {p}") print(f"獲取pid: {p.pid}") print(f"獲取返回?cái)?shù)據(jù): {p.stdout.read()}") p.wait() print(f"獲取執(zhí)行狀態(tài): {p.poll()}")3.2 執(zhí)行結(jié)果:
獲取返回對(duì)象: <subprocess.Popen object at 0x0028C4B0> 獲取pid: 5260 獲取返回?cái)?shù)據(jù): chinablue 獲取執(zhí)行狀態(tài): 03.3 分析小結(jié):
1 ) subprocess.Popen()方法是一個(gè)異步方法,執(zhí)行后會(huì)返回一個(gè)Popen對(duì)象
2 ) 獲取子進(jìn)程的標(biāo)準(zhǔn)輸出(stdout)和標(biāo)準(zhǔn)錯(cuò)誤(stderr)
方式1:通過p.stdout和p.stderr獲取,如上例所示
方式2:通過p.communicate()獲取,它返回一個(gè)元祖,元祖的第1個(gè)元素為stdout內(nèi)容,元祖的第2個(gè)元素為stderr內(nèi)容
p = subprocess.Popen("echo chinablue", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) print(f"獲取返回?cái)?shù)據(jù): {p.communicate()[0]}") print(f"獲取返回錯(cuò)誤: {p.communicate()[1]}")3 ) 獲取命令的執(zhí)行狀態(tài):p.poll()
如果執(zhí)行完subprocess.Popen()方法后,立即獲取命令的執(zhí)行狀態(tài), 則返回結(jié)果為None,因?yàn)榇藭r(shí)子進(jìn)程扔在運(yùn)行中
如果我們需要等待子進(jìn)程運(yùn)行完畢后,再去獲取命令的執(zhí)行狀態(tài)。那么我們可以使用p.wait()方法,這相當(dāng)于將默認(rèn)的異步操作改為同步操作
p = subprocess.Popen("echo chinablue", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) print(p.poll()) # 運(yùn)行結(jié)果: None p.wait() print(p.poll()) # 運(yùn)行結(jié)果: 0四. 常見場景舉例
場景1:在windows下,執(zhí)行ipconfig命令并對(duì)結(jié)果進(jìn)行過濾
# -*- coding:utf-8 -*- # 遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:778463939 # 尋找有志同道合的小伙伴,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! import subprocess# 步驟1:將ipconfig命令的執(zhí)行結(jié)果寫入output.txt文件 with open("output.txt", "w") as f:subprocess.run("ipconfig", shell=True, stdout=f, universal_newlines=True, encoding="utf-8") # 步驟2:將p1的輸出內(nèi)容作為p2的輸入內(nèi)容 p1 = subprocess.run("type output.txt", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) p2 = subprocess.run("findstr IPv4", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, input=p1.stdout) print(p2.stdout)場景2:在windows下,模擬并發(fā)執(zhí)行命令
# -*- coding:utf-8 -*- # 遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:778463939 # 尋找有志同道合的小伙伴,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! import time import subprocess# 模擬一條耗時(shí)命令,此命令在windows下執(zhí)行相當(dāng)于sleep 2s cmd = "ping -n 3 127.0.0.1 > nul"start_time = time.time() p1 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) p2 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) p1.wait() p2.wait() print(f"運(yùn)行時(shí)間共計(jì):{int(time.time() - start_time)}s") # p1和p2命令執(zhí)行各需耗時(shí)2s,通過并發(fā)執(zhí)行后共計(jì)耗時(shí)也是2s場景3:自動(dòng)處理命令行交互
# -*- coding: utf-8 -*- import subprocess# 這是一條對(duì)視頻文件進(jìn)行處理的命令(改變視頻分辨率,同時(shí)將視頻設(shè)置為倍速播放) cmd = f'ffmpeg -i "dj_xiaomi.mp4" -s vga -filter:v "setpts=0.5*PTS" output.mp4' p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)# 命令在執(zhí)行過程中,如果本地已經(jīng)存在有output.mp4文件, 那么命令行處會(huì)出現(xiàn)提示符: File 'output.mp4' already exists. Overwrite? [y/N] buff = '' while True:output = p.stdout.read(1)if output:buff += outputelse:break# 出現(xiàn)提示符([y/N])后,程序可以自行處理此交互行為if buff.endswith("[y/N]"):p.communicate(input="y")break另外python中的pexpect模塊更擅長解決命令行的自動(dòng)交互問題
總結(jié)
以上是生活随笔為你收集整理的python3中使用subprocess模块执行外部命令的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python教程:对 a = [lamb
- 下一篇: python中将函数赋值给变量时需要注意