感谢Python标准库-SubProcess 提供的视频,本笔记仅仅用于自我记录,内容和视频一致
概述
subprocess 是Py调用外部工具的终极武器
在写 Python 代码时,你一定遇到过这些场景:
-
想调用系统工具(如
git、ffmpeg、ping); -
想执行 Shell 命令批量处理文件;
-
想运行其他程序或脚本,并获取它的输出;
-
旧的
os.system()、os.popen()要么不安全,要么功能不够用。 -
调用cmd
概述
其实你并不需要知道他有什么好处你只需要知道,他是一种调用外部工具的方法,以及怎么掌握调用外部工具就够了。
上面几种情况就需要 subprocess 标准库!它是 Python 3 推荐的执行外部命令 的库,功能强大、安全可控、跨平台兼容,能完全替代旧的 os.system()、os.popen() 等方法!
本节课我们重点学习 subprocess 的核心功能:从基础的运行命令,到获取输出、处理错误、高级交互,最后还有一个综合实战案例!
代码演示
获取命令输入
1、核心概念和安全注意事项
- 创建新的子进程,用来和新的子进程进行交互,获取子进程的输入、输出、错误和检查状态码。
- 尽量不要使用shell=True这个特性
2、基础操作
如何运行外部命令 subprocess.run()实现
subprocess.run(args,shell=True/False,check=False/True,capture_output=False/True,text=False/True)
py
"""
subprocess 标准库学习
"""
import subprocess
# 1、核心概念和安全注意事项
# 创建新的子进程,用来和新的子进程进行交互,获取子进程的输入、输出、错误和检查状态码。
# 尽量不要使用shell=True这个特性
# 2、基础操作
# 如何运行外部命令 subprocess.run()实现
# subprocess.run(args,shell=True/False,check=False/True,capture_output=False/True,text=False/True)
# 查看当前目录下,有哪些文件和文件夹
result = subprocess.run(["dir"], shell=True)
print(f"result:>>>\n{result}")

小附录
平时写代码常用的参数有:
| 参数 | 作用 |
|---|---|
args |
要执行的命令(列表或字符串),例如dir 是 Windows 系统的命令 ,用来列出当前目录下的文件和文件夹 (相当于 Linux/Mac 下的 ls 命令)。 |
shell=True |
是否通过系统shell执行(不推荐,有安全风险) |
check=True |
如果命令执行失败(非0退出码),抛出异常 |
capture_output=True |
捕获命令的输出和错误信息 |
text=True |
输出以字符串形式返回(否则是字节) |
input |
给子进程提供输入数据 |
env |
设置子进程的环境变量 |
核心概念和注意
1. subprocess 的作用
subprocess 用于在 Python 进程中创建新的子进程,执行外部命令或程序,并与它们交互(传递输入、获取输出 / 错误、检查返回码)。
2. 核心函数
-
subprocess.run()(推荐,Python 3.5+):最常用的函数,封装了大多数场景,简单易用。 -
subprocess.Popen(高级用法):底层类,更灵活,适合需要实时交互、长时间运行的命令。
3. ⚠️ 安全警告:避免命令注入
-
尽量不要用 ****
shell=True:除非必须用 Shell 特性(如管道、通配符),否则用命令列表 (如['ls', '-l']),避免命令注入攻击。 -
命令注入示例(危险!):如果用户输入
"; rm -rf /",用shell=True会执行恶意命令!
运行外部命令(subprocess.run())
核心知识点
subprocess.run(args, ...) 是最基础的函数,参数:
-
args:命令(推荐用列表 ,如['ls', '-l'];也可以是字符串,但需配合shell=True)。 -
shell:是否通过 Shell 执行(默认False,尽量保持 ****False)。 -
check:是否检查返回码(默认False;设为True时,命令失败会抛出CalledProcessError)。 -
capture_output:是否捕获标准输出 / 错误(默认False)。 -
text(或universal_newlines):是否用文本模式(默认False,输出是bytes;设为True输出是字符串)。
示例代码
python
import subprocess
import sys
# ====================== 1. 运行简单命令(不捕获输出) ======================
print("===== 1. 运行 ls/dir 命令 =====")
# 适配 Windows 和 Linux/macOS
if sys.platform == "win32":
# Windows 用 dir
result = subprocess.run(["dir"], shell=True) # Windows 下 dir 是 Shell 内置命令,需 shell=True
else:
# Linux/macOS 用 ls
result = subprocess.run(["ls", "-l"])
# 返回的是 CompletedProcess 对象
print("n命令参数:", result.args)
print("返回码(0=成功,非0=失败):", result.returncode)
# ====================== 2. 用 shell=True(仅当必要时!) ======================
print("n===== 2. 用 Shell 特性(如通配符) =====")
if sys.platform == "win32":
# Windows 用 dir *.py
result = subprocess.run("dir *.py", shell=True)
else:
# Linux/macOS 用 ls *.py
result = subprocess.run("ls *.py", shell=True)
内容讲解
-
命令列表 vs 字符串:
-
列表(如
['ls', '-l']):更安全,避免命令注入,推荐优先使用。 -
字符串(如
'ls -l'):需配合shell=True,仅当需要 Shell 特性(如通配符*、管道|、重定向>)时使用。
-
-
Windows 注意事项 :
dir、copy等是 Shell 内置命令,必须用shell=True;而ping、git等是独立程序,不用shell=True。 -
返回码 :
returncode=0表示命令成功,非 0 表示失败(不同命令的失败码含义不同)。
获取命令的输出(最常用场景!)
核心知识点
要获取命令的输出,用:
-
capture_output=True:同时捕获stdout(标准输出)和stderr(标准错误)。 -
或者单独指定
stdout=subprocess.PIPE、stderr=subprocess.PIPE。 -
必须加 ****
text=True:否则输出是bytes类型(需要手动decode())。
示例代码
python
import subprocess
import sys
print("===== 获取命令输出 =====")
# 示例1:获取 ls -l / dir 的输出
if sys.platform == "win32":
cmd = ["cmd", "/c", "dir"] # Windows 下用 cmd /c 执行 dir,避免 shell=True
else:
cmd = ["ls", "-l"]
# 捕获输出,文本模式
result = subprocess.run(
cmd,
capture_output=True,
text=True,
check=True # 命令失败则抛出异常
)
print("标准输出:")
print(result.stdout)
print("标准错误:")
print(result.stderr) # 成功时通常为空
# 示例2:获取 ping 的输出(注意平台参数差异)
print("n===== Ping 测试 =====")
if sys.platform == "win32":
# Windows: ping -n 2 www.baidu.com
ping_cmd = ["ping", "-n", "2", "www.baidu.com"]
else:
# Linux/macOS: ping -c 2 www.baidu.com
ping_cmd = ["ping", "-c", "2", "www.baidu.com"]
ping_result = subprocess.run(
ping_cmd,
capture_output=True,
text=True
)
print("Ping 输出:")
print(ping_result.stdout)
内容讲解
-
stdout:命令的正常输出(如ls的文件列表)。 -
stderr:命令的错误信息(如文件不存在时的提示)。 -
text=True:Python 3.7+ 推荐用text,旧版本用universal_newlines(效果一样)。 -
Windows 下执行
dir的技巧 :不用shell=True,而是用["cmd", "/c", "dir"],更安全。
下面是原版
B 站 Python 授课:subprocess 标准库 ------Python 调用外部命令的 "终极武器"
课程导入
在写 Python 代码时,你一定遇到过这些场景:
-
想调用系统工具(如
git、ffmpeg、ping); -
想执行 Shell 命令批量处理文件;
-
想运行其他程序或脚本,并获取它的输出;
-
旧的
os.system()、os.popen()要么不安全,要么功能不够用。
这时候就需要 subprocess 标准库!它是 Python 3 推荐的执行外部命令 的库,功能强大、安全可控、跨平台兼容,能完全替代旧的 os.system()、os.popen() 等方法!
本节课我们重点学习 subprocess 的核心功能:从基础的运行命令,到获取输出、处理错误、高级交互,最后还有一个综合实战案例!
第一部分:核心概念与安全注意事项
1. subprocess 的作用
subprocess 用于在 Python 进程中创建新的子进程,执行外部命令或程序,并与它们交互(传递输入、获取输出 / 错误、检查返回码)。
2. 核心函数
-
subprocess.run()(推荐,Python 3.5+):最常用的函数,封装了大多数场景,简单易用。 -
subprocess.Popen(高级用法):底层类,更灵活,适合需要实时交互、长时间运行的命令。
3. ⚠️ 安全警告:避免命令注入
-
尽量不要用 ****
shell=True:除非必须用 Shell 特性(如管道、通配符),否则用命令列表 (如['ls', '-l']),避免命令注入攻击。 -
命令注入示例(危险!):如果用户输入
"; rm -rf /",用shell=True会执行恶意命令!
第二部分:基础操作:运行外部命令(subprocess.run())
核心知识点
subprocess.run(args, ...) 是最基础的函数,参数:
-
args:命令(推荐用列表 ,如['ls', '-l'];也可以是字符串,但需配合shell=True)。 -
shell:是否通过 Shell 执行(默认False,尽量保持 ****False)。 -
check:是否检查返回码(默认False;设为True时,命令失败会抛出CalledProcessError)。 -
capture_output:是否捕获标准输出 / 错误(默认False)。 -
text(或universal_newlines):是否用文本模式(默认False,输出是bytes;设为True输出是字符串)。
示例代码
python
import subprocess
import sys
# ====================== 1. 运行简单命令(不捕获输出) ======================
print("===== 1. 运行 ls/dir 命令 =====")
# 适配 Windows 和 Linux/macOS
if sys.platform == "win32":
# Windows 用 dir
result = subprocess.run(["dir"], shell=True) # Windows 下 dir 是 Shell 内置命令,需 shell=True
else:
# Linux/macOS 用 ls
result = subprocess.run(["ls", "-l"])
# 返回的是 CompletedProcess 对象
print("n命令参数:", result.args)
print("返回码(0=成功,非0=失败):", result.returncode)
# ====================== 2. 用 shell=True(仅当必要时!) ======================
print("n===== 2. 用 Shell 特性(如通配符) =====")
if sys.platform == "win32":
# Windows 用 dir *.py
result = subprocess.run("dir *.py", shell=True)
else:
# Linux/macOS 用 ls *.py
result = subprocess.run("ls *.py", shell=True)
内容讲解
-
命令列表 vs 字符串:
-
列表(如
['ls', '-l']):更安全,避免命令注入,推荐优先使用。 -
字符串(如
'ls -l'):需配合shell=True,仅当需要 Shell 特性(如通配符*、管道|、重定向>)时使用。
-
-
Windows 注意事项 :
dir、copy等是 Shell 内置命令,必须用shell=True;而ping、git等是独立程序,不用shell=True。 -
返回码 :
returncode=0表示命令成功,非 0 表示失败(不同命令的失败码含义不同)。
第三部分:获取命令的输出(最常用场景!)
核心知识点
要获取命令的输出,用:
-
capture_output=True:同时捕获stdout(标准输出)和stderr(标准错误)。 -
或者单独指定
stdout=subprocess.PIPE、stderr=subprocess.PIPE。 -
必须加 ****
text=True:否则输出是bytes类型(需要手动decode())。
示例代码
python
import subprocess
import sys
print("===== 获取命令输出 =====")
# 示例1:获取 ls -l / dir 的输出
if sys.platform == "win32":
cmd = ["cmd", "/c", "dir"] # Windows 下用 cmd /c 执行 dir,避免 shell=True
else:
cmd = ["ls", "-l"]
# 捕获输出,文本模式
result = subprocess.run(
cmd,
capture_output=True,
text=True,
check=True # 命令失败则抛出异常
)
print("标准输出:")
print(result.stdout)
print("标准错误:")
print(result.stderr) # 成功时通常为空
# 示例2:获取 ping 的输出(注意平台参数差异)
print("n===== Ping 测试 =====")
if sys.platform == "win32":
# Windows: ping -n 2 www.baidu.com
ping_cmd = ["ping", "-n", "2", "www.baidu.com"]
else:
# Linux/macOS: ping -c 2 www.baidu.com
ping_cmd = ["ping", "-c", "2", "www.baidu.com"]
ping_result = subprocess.run(
ping_cmd,
capture_output=True,
text=True
)
print("Ping 输出:")
print(ping_result.stdout)
内容讲解
-
stdout:命令的正常输出(如ls的文件列表)。 -
stderr:命令的错误信息(如文件不存在时的提示)。 -
text=True:Python 3.7+ 推荐用text,旧版本用universal_newlines(效果一样)。 -
Windows 下执行
dir的技巧 :不用shell=True,而是用["cmd", "/c", "dir"],更安全。
第四部分:错误处理与返回码
核心知识点
-
check=True:如果命令返回码非 0(失败),会抛出subprocess.CalledProcessError异常。 -
捕获
CalledProcessError可以获取失败时的returncode、stdout、stderr。 -
如果不用
check=True,需要手动检查result.returncode。
示例代码
python
import subprocess
print("===== 错误处理 =====")
# 示例:运行一个不存在的命令
try:
result = subprocess.run(
["不存在的命令"],
capture_output=True,
text=True,
check=True # 失败则抛出异常
)
except FileNotFoundError:
print("❌ 错误:命令不存在!")
except subprocess.CalledProcessError as e:
print(f"❌ 命令失败,返回码:{e.returncode}")
print(f"错误输出:{e.stderr}")
else:
print("✅ 命令成功!")
print("输出:", result.stdout)
# 示例:手动检查返回码(不用 check=True)
print("n===== 手动检查返回码 =====")
result = subprocess.run(["ls", "不存在的文件"], capture_output=True, text=True)
if result.returncode == 0:
print("✅ 成功")
else:
print(f"❌ 失败,返回码:{result.returncode}")
print(f"错误:{result.stderr}")
内容讲解
-
常见异常:
-
FileNotFoundError:命令不存在(如拼写错误)。 -
CalledProcessError:命令存在但执行失败(如check=True时返回码非 0)。
-
-
手动检查 vs ****
check=True:-
check=True适合 "命令必须成功,否则中断程序" 的场景。 -
手动检查适合 "命令失败也没关系,需要根据返回码做不同处理" 的场景。
-
第五部分:给命令提供输入
核心知识点
用 input 参数给命令传递输入(文本模式下是字符串,二进制模式下是 bytes)。
- 适合需要交互式输入的命令(如
python解释器、ssh等)。
示例代码
python
import subprocess
print("===== 给命令提供输入 =====")
# 示例:给 Python 解释器输入代码
python_code = """
print("Hello from subprocess!")
print(1 + 2 + 3)
"""
result = subprocess.run(
["python"],
input=python_code,
capture_output=True,
text=True
)
print("Python 命令的输出:")
print(result.stdout)
内容讲解
-
input参数会替代标准输入(sys.stdin),命令会从这里读取输入,而不是等待键盘输入。 -
必须配合
text=True(如果输入是字符串)或传递bytes(如input=b"hellon")。
第六部分:高级用法:Popen 类(实时交互 / 长时间运行)
核心知识点
subprocess.Popen 是底层类,比 run() 更灵活,适合:
-
需要实时获取输出的场景(如长时间运行的命令,边运行边打印输出)。
-
需要与命令持续交互的场景(如发送多次输入)。
常用方法 / 属性
| 方法 / 属性 | 说明 |
|---|---|
Popen.poll() |
检查命令是否完成(返回 None 表示未完成,返回 returncode 表示已完成) |
Popen.wait() |
等待命令完成(会阻塞) |
Popen.communicate(input=None) |
发送输入,获取输出 / 错误(会阻塞,适合一次性交互) |
Popen.stdout / Popen.stderr |
标准输出 / 错误的文件对象(可实时读取) |
示例代码
python
import subprocess
import sys
import time
print("===== Popen 实时获取输出 =====")
# 示例:运行 ping 命令,实时打印输出
if sys.platform == "win32":
ping_cmd = ["ping", "-n", "4", "www.baidu.com"]
else:
ping_cmd = ["ping", "-c", "4", "www.baidu.com"]
# 创建 Popen 对象,stdout=subprocess.PIPE,text=True
with subprocess.Popen(
ping_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
bufsize=1, # 行缓冲
universal_newlines=True
) as proc:
# 实时读取 stdout
print("Ping 实时输出:")
for line in proc.stdout:
print(line, end="") # end="" 避免重复换行
# 等待命令完成,获取 stderr
stderr = proc.communicate()[1]
if stderr:
print("n错误输出:", stderr)
print(f"n返回码:{proc.returncode}")
内容讲解
-
with语句:自动管理Popen对象,确保资源释放。 -
bufsize=1:行缓冲,让输出实时显示(否则可能会等命令完成才一次性显示)。 -
communicate():适合一次性发送输入并获取输出,会阻塞直到命令完成。
第七部分:常见应用场景
-
调用系统工具 :如
git status、ffmpeg转码、tar压缩文件。 -
批量处理文件:结合 Shell 命令批量重命名、转换文件格式。
-
检查系统状态 :如
ping测试网络、df查看磁盘空间、ps查看进程。 -
调用其他脚本 / 程序:运行其他 Python 脚本、可执行文件,并获取结果。
-
自动化任务 :结合
cron(Linux)或任务计划程序(Windows),定时执行命令。
第八部分:实战案例 ------ 简易 "系统命令执行器"
功能需求
结合 subprocess.run()、Popen、跨平台适配,实现一个工具:
-
支持执行常见命令:
-
list:列出当前目录文件(ls/dir); -
ping <host>:Ping 测试; -
git:执行git status(如果有 git);
-
-
跨平台适配(Windows/Linux/macOS);
-
捕获输出和错误,友好显示;
-
安全限制(只允许执行指定命令,避免任意命令执行)。
完整实战代码
python
import subprocess
import sys
class SimpleCommandRunner:
def __init__(self):
self.platform = sys.platform
def run_list(self):
"""列出当前目录文件"""
print("===== 列出当前目录 =====")
if self.platform == "win32":
cmd = ["cmd", "/c", "dir"]
else:
cmd = ["ls", "-l"]
self._run_cmd(cmd)
def run_ping(self, host):
"""Ping 测试"""
print(f"===== Ping {host} =====")
if self.platform == "win32":
cmd = ["ping", "-n", "3", host]
else:
cmd = ["ping", "-c", "3", host]
self._run_cmd(cmd)
def run_git_status(self):
"""执行 git status"""
print("===== Git Status =====")
try:
self._run_cmd(["git", "status"])
except FileNotFoundError:
print("❌ 错误:未找到 git 命令,请先安装 git")
def _run_cmd(self, cmd):
"""内部方法:执行命令并显示结果"""
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
check=True
)
print("✅ 命令成功!")
print("输出:")
print(result.stdout)
if result.stderr:
print("警告:", result.stderr)
except subprocess.CalledProcessError as e:
print(f"❌ 命令失败,返回码:{e.returncode}")
print("错误输出:", e.stderr)
except Exception as e:
print(f"❌ 发生错误:{str(e)}")
def show_usage(self):
"""显示用法"""
print("===== 简易系统命令执行器 =====")
print("用法:python command_runner.py <命令> [参数]")
print("支持的命令:")
print(" list 列出当前目录文件")
print(" ping <host> Ping 测试(如 ping www.baidu.com)")
print(" git 执行 git status")
print(" help 显示此帮助")
def run(self):
"""主逻辑"""
if len(sys.argv) < 2:
self.show_usage()
return
command = sys.argv[1]
if command == "list":
self.run_list()
elif command == "ping":
if len(sys.argv) < 3:
print("❌ 错误:ping 命令需要主机参数(如 ping www.baidu.com)")
return
host = sys.argv[2]
self.run_ping(host)
elif command == "git":
self.run_git_status()
elif command == "help":
self.show_usage()
else:
print(f"❌ 错误:未知命令 '{command}'")
self.show_usage()
# ========== 运行工具 ==========
if __name__ == '__main__':
runner = SimpleCommandRunner()
runner.run()
运行方式(命令行)
bash
# 列出目录
python command_runner.py list
# Ping 测试
python command_runner.py ping www.baidu.com
# Git status
python command_runner.py git
# 显示帮助
python command_runner.py help
代码讲解
-
面向对象封装 :把所有功能封装在
SimpleCommandRunner类里,结构清晰。 -
跨平台适配 :根据
sys.platform选择不同的命令(如dirvsls,-nvs-c)。 -
安全限制 :只允许执行指定的命令(
list/ping/git),避免用户执行任意命令。 -
友好的错误处理 :捕获
FileNotFoundError、CalledProcessError等异常,给用户清晰的提示。 -
内部方法 ****
_run_cmd:封装通用的命令执行逻辑,避免代码重复。
课程总结与避坑指南
核心知识点回顾
| 功能 | 方法 / 类 | 说明 |
|---|---|---|
| 基础运行命令 | subprocess.run() |
推荐,Python 3.5+ |
| 获取输出 | capture_output=True + text=True |
输出是字符串 |
| 错误处理 | check=True + 捕获 CalledProcessError |
命令失败时抛出异常 |
| 提供输入 | input 参数 |
替代标准输入 |
| 高级交互 | subprocess.Popen |
实时输出、长时间运行 |
避坑指南
-
安全第一:
-
尽量用命令列表 (如
['ls', '-l']),避免shell=True。 -
不要让用户输入任意命令,限制可执行的命令范围。
-
-
平台差异:
-
Windows 下注意
dir等内置命令需用cmd /c。 -
ping、ls等命令的参数在不同平台可能不同。
-
-
文本模式:
- 记得加
text=True,否则输出是bytes,需要手动decode()。
- 记得加
-
资源管理:
-
用
with语句管理Popen对象,确保资源释放。 -
长时间运行的命令注意实时读取输出,避免缓冲区填满导致阻塞。
-