Python使用subprocess模塊輕松調(diào)用外部程序與命令
01 subprocess模塊簡介
subprocess是Python的標準庫,它的設(shè)計目標是替代舊有的os.system、os.popen等模塊,提供更統(tǒng)一、更強大的子進程管理功能。使用subprocess可以啟動外部程序、獲取程序執(zhí)行結(jié)果、管理進程的輸入輸出和錯誤信息,在自動化腳本、系統(tǒng)管理、程序集成等場景中發(fā)揮重要作用。
02 核心函數(shù)介紹與案例
1. subprocess.run():執(zhí)行命令并等待完成
subprocess.run()是subprocess模塊中最常用的函數(shù),用于執(zhí)行指定的命令,并等待命令執(zhí)行完畢。它接受args參數(shù)(命令及其參數(shù)),以及input等可選參數(shù),返回一個CompletedProcess對象,包含命令執(zhí)行結(jié)果信息。
參數(shù)介紹:
1)popenargs:指定要執(zhí)行的命令及參數(shù)
popenargs是subprocess.run()中最核心的參數(shù),必須傳入,它用于指定要執(zhí)行的外部命令及其參數(shù)。args通常以列表形式傳遞,列表的第一個元素是命令本身,后續(xù)元素為命令的參數(shù)。
案例:執(zhí)行簡單命令
import subprocess
# 執(zhí)行l(wèi)s命令,獲取當前目錄下的文件列表
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
if result.returncode == 0:
print("命令執(zhí)行成功,輸出如下:")
print(result.stdout)
else:
print(f"命令執(zhí)行失敗,錯誤信息:{result.stderr}")說明:代碼中使用subprocess.run()執(zhí)行l(wèi)s -l命令,capture_output=True表示捕獲命令的標準輸出和標準錯誤輸出,text=True則以文本形式返回輸出結(jié)果。通過檢查returncode判斷命令是否執(zhí)行成功。
2)stdin、stdout、stderr:控制輸入輸出和錯誤流
- stdin:指定子進程的標準輸入,可以是文件對象、字節(jié)串或字符串(當text=True時)。如果不指定,子進程的標準輸入將繼承父進程的標準輸入。
- stdout:指定子進程的標準輸出,常見取值為subprocess.PIPE(用于捕獲輸出)、文件對象或None(默認繼承父進程的標準輸出)。
- stderr:指定子進程的標準錯誤輸出,取值和用法與stdout類似。
案例:捕獲命令的輸出和錯誤信息
import subprocess
# 執(zhí)行一個錯誤的命令,捕獲輸出和錯誤
result = subprocess.run(['ls', 'nonexistent_file'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
print("標準輸出:", result.stdout)
print("標準錯誤:", result.stderr)
#輸出為:
標準輸出:
標準錯誤: ls: nonexistent_file: No such file or directory3)capture_output:快速捕獲輸出和錯誤
capture_output是一個布爾值參數(shù),當設(shè)置為True時,相當于同時將stdout和stderr設(shè)置為subprocess.PIPE,并自動捕獲子進程的標準輸出和標準錯誤。
案例:使用capture_output簡化代碼
import subprocess
# 執(zhí)行一個錯誤的命令,捕獲輸出和錯誤
result = subprocess.run(['ls', 'nonexistent_file'],capture_output=True, text=True)
print("標準輸出:", result.stdout)
print("標準錯誤:", result.stderr)4)shell:使用系統(tǒng)shell執(zhí)行命令
shell是一個布爾值參數(shù),默認為False。當shell=True時,命令會通過系統(tǒng)的shell(如bash)執(zhí)行,此時執(zhí)行命令可以是字符串形式,如下“ls nonexistent_file”。
import subprocess
# 執(zhí)行一個錯誤的命令,捕獲輸出和錯誤
result = subprocess.run('ls nonexistent_file',shell=True,capture_output=True, text=True)
print("標準輸出:", result.stdout)
print("標準錯誤:", result.stderr)但這種方式可能會引入安全問題,例如:
import subprocess
user_input = "; rm -rf /"# 惡意輸入示例
# 危險操作!可能會刪除系統(tǒng)根目錄
subprocess.run(f'echo {user_input}', shell=True)因此,除非必要,否則不建議使用shell=True,若確實需要,可以考慮使用shlex.quote對輸入進行轉(zhuǎn)義。
5)cwd:指定子進程的工作目錄
cwd參數(shù)用于指定子進程執(zhí)行時的工作目錄。如果不指定,子進程將在父進程的當前工作目錄下執(zhí)行。
案例:在指定目錄下執(zhí)行命令
import subprocess # 在/tmp目錄下執(zhí)行l(wèi)s命令 result = subprocess.run(['ls'], cwd='/tmp', capture_output=True, text=True) print(result.stdout)
6)timeout:設(shè)置命令執(zhí)行的超時時間
timeout參數(shù)用于設(shè)置子進程執(zhí)行的最長時間(單位為秒)。如果子進程在指定時間內(nèi)未執(zhí)行完畢,將引發(fā)subprocess.TimeoutExpired異常。
案例:設(shè)置命令執(zhí)行超時
import subprocess
try:
# 執(zhí)行ping命令,設(shè)置超時時間為5秒
result = subprocess.run(['ping', 'www.baidu.com'], timeout=5, capture_output=True, text=True)
print(result.stdout)
except subprocess.TimeoutExpired:
print("命令執(zhí)行超時!")7)check:檢查命令執(zhí)行狀態(tài)
check是一個布爾值參數(shù),默認為False。當check=True時,如果子進程的返回碼不為0,將引發(fā)
subprocess.CalledProcessError異常。
案例:檢查命令是否執(zhí)行成功
import subprocess
try:
# 執(zhí)行一個可能失敗的命令,開啟check檢查
result = subprocess.run(['ls','nonexistent_file'], check=True, capture_output=True, text=True)
except subprocess.CalledProcessError:
print("命令執(zhí)行失?。?)2. subprocess.Popen():創(chuàng)建并管理子進程
subprocess.Popen()函數(shù)用于創(chuàng)建一個新的子進程,并返回一個Popen對象,通過該對象可以控制子進程的執(zhí)行、獲取輸出、與子進程進行交互。
subprocess.Popen()是subprocess模塊的底層接口,與run()的主要區(qū)別在于:
- 阻塞 vs 非阻塞:run()是阻塞式的(等待命令執(zhí)行完畢),而Popen()是非阻塞式的(立即返回進程對象)。
- 靈活性:Popen()提供更底層的控制,適合需要實時交互或復(fù)雜進程管理的場景。
參數(shù)介紹:
1)args:命令及參數(shù)
與run()相同,指定要執(zhí)行的命令。推薦使用列表形式,避免安全風險。
import subprocess
# 正確寫法:列表形式
p = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
# 危險寫法(shell=True):
# p = subprocess.Popen('ls -l', shell=True)2)stdin/stdout/stderr:控制輸入輸出
與run()類似,但更靈活,支持實時處理流數(shù)據(jù)。
常見取值:
- subprocess.PIPE:創(chuàng)建管道,用于捕獲輸出或提供輸入。
- 文件對象:將輸出 / 輸入重定向到文件。
- None(默認):繼承父進程。
案例:實時獲取命令輸出
import subprocess
# 執(zhí)行命令并實時獲取輸出
p = subprocess.Popen(['ping', 'www.baidu.com'], stdout=subprocess.PIPE, text=True)
# 逐行讀取輸出
for line in iter(p.stdout.readline, ''):
print(line.strip())
p.wait() # 等待進程結(jié)束3)shell:通過shell執(zhí)行命令(慎用)
與run()的shell參數(shù)功能相同,但風險更高。僅在必要時使用,并確保輸入經(jīng)過嚴格過濾。
# 安全風險示例(切勿在生產(chǎn)環(huán)境使用)
user_input = "example.txt; rm -rf /"
subprocess.Popen(f'cat {user_input}', shell=True)4)cwd:指定工作目錄
與run()的cwd參數(shù)功能相同。
import subprocess # 在/tmp目錄下執(zhí)行命令 p = subprocess.Popen(['ls'], cwd='/tmp', stdout=subprocess.PIPE) print(p.stdout.read().decode())
5)env:自定義環(huán)境變量
覆蓋或添加子進程的環(huán)境變量。(有些命令執(zhí)行時需要獲取環(huán)境變量信息,否則執(zhí)行shell命令可能會報錯)
import subprocess
import os
# 自定義環(huán)境變量
my_env = {**os.environ, 'MY_VAR': 'custom_value'}
p = subprocess.Popen(['printenv', 'MY_VAR'], env=my_env, stdout=subprocess.PIPE)
print(p.stdout.read().decode()) # 輸出: custom_value6)bufsize:控制緩沖區(qū)大小
- -1(默認):使用系統(tǒng)默認緩沖區(qū)大小。
- 0:無緩沖(僅適用于stdin、stdout、stderr為管道時)。
- 1:行緩沖(僅在text=True時有效)。
- >1:指定緩沖區(qū)大?。ㄗ止?jié))。
# 無緩沖模式,實時獲取輸出 p = subprocess.Popen(['ls'], stdout=subprocess.PIPE, bufsize=0)
7)start_new_session(Windows/Linux)
在新會話中啟動進程。
# 在Windows或Linux上創(chuàng)建新會話 p = subprocess.Popen(['python', 'script.py'], start_new_session=True)
一些應(yīng)用場景
1). 實時監(jiān)控命令輸出
import subprocess
# 實時監(jiān)控日志文件
p = subprocess.Popen(['tail', '-f', '/var/log/syslog'], stdout=subprocess.PIPE, text=True)
try:
for line in iter(p.stdout.readline, ''):
print(f"日志: {line.strip()}")
except KeyboardInterrupt:
p.terminate() # 按Ctrl+C終止監(jiān)控2). 并行執(zhí)行多個命令
import subprocess
import time
# 并行執(zhí)行多個命令
commands = [
['sleep', '2'],
['ls', '-l'],
['echo', 'Hello']
]
processes = [subprocess.Popen(cmd) for cmd in commands]
# 等待所有進程結(jié)束
for p in processes:
p.wait()
print("所有命令執(zhí)行完畢")3). 復(fù)雜交互場景(如FTP客戶端)
import subprocess
# 啟動交互式FTP客戶端
p = subprocess.Popen(['ftp', 'ftp.example.com'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,text=True)
# 發(fā)送登錄命令
p.stdin.write('user\n')
p.stdin.write('password\n')
p.stdin.flush()
# 讀取響應(yīng)
output = p.stdout.read(1024)Popen對象的其他方法
方法 | 描述 |
p.wait(timeout) | 等待進程結(jié)束并返回返回碼,可設(shè)置超時(超時拋出TimeoutExpired)。 |
p.communicate(input=None, timeout=None) | 與進程交互(發(fā)送輸入、獲取輸出),等待進程結(jié)束。 |
p.send_signal(signal) | 向進程發(fā)送信號(如signal.SIGTERM)。 |
p.terminate() | 終止進程(發(fā)送 SIGTERM 信號)。 |
p.kill() | 強制殺死進程(發(fā)送 SIGKILL 信號)。 |
p.poll() | 檢查進程是否結(jié)束,返回返回碼(未結(jié)束返回None)。 |
3. subprocess.check_output():執(zhí)行命令并返回輸出
subprocess.check_output()函數(shù)執(zhí)行指定命令,若命令執(zhí)行成功,返回命令的標準輸出;若執(zhí)行失敗(返回碼非 0),則拋出CalledProcessError異常。
案例:獲取系統(tǒng)磁盤空間信息
import subprocess
try:
result = subprocess.check_output(['df', '-h'], text=True)
print("磁盤空間信息:")
print(result)
except subprocess.CalledProcessError as e:
print(f"命令執(zhí)行失敗,錯誤碼:{e.returncode},錯誤信息:{e.output}")說明:代碼執(zhí)行df -h命令獲取磁盤空間信息,若命令執(zhí)行失敗,捕獲異常并輸出錯誤信息。
subprocess模塊賦予了Python與外部世界交互的強大能力,通過掌握這些核心函數(shù),我們可以在 Python開發(fā)中實現(xiàn)更豐富的功能,無論是自動化運維、數(shù)據(jù)采集,還是程序集成,subprocess都能成為你的得力助手。
以上就是Python使用subprocess模塊輕松調(diào)用外部程序與命令的詳細內(nèi)容,更多關(guān)于Python subprocess調(diào)用外部程序與命令的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
利用Python對文件夾下圖片數(shù)據(jù)進行批量改名的代碼實例
今天小編就為大家分享一篇關(guān)于利用Python對文件夾下圖片數(shù)據(jù)進行批量改名的代碼實例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-02-02
Python腳本實現(xiàn)掃描指定目錄下.py文件并提取import語句
這篇文章主要為大家詳細介紹了如何使用Python腳本實現(xiàn)掃描指定目錄下.py文件并提取import語句,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下2026-03-03

