Python subprocess模块完全指南
专为编程新手设计的通俗易懂知识点汇总
什么是subprocess模块?
简单来说,subprocess模块是Python中用来启动和控制其他程序的工具。就像你在电脑上双击打开一个应用程序一样,Python可以用这个模块来运行其他程序。
为什么需要subprocess?
想象你想在Python程序中:
- 运行一个系统命令(比如
dir
或ls
) - 启动另一个Python脚本
- 调用一个外部程序(如记事本、计算器等)
- 获取命令执行的结果
subprocess就是做这些事情的”桥梁”!
核心功能:运行外部命令
run()函数(推荐使用)
最简单安全的运行命令的方式,适合大多数情况。
它会等待命令完成后返回结果,可以获取输出和状态码。
import subprocess
# 运行简单命令
result = subprocess.run([“ls”, “-l”])
# 获取命令输出
result = subprocess.run([“echo”, “Hello World”],
capture_output=True, text=True)
print(result.stdout) # 输出: Hello World
# 运行简单命令
result = subprocess.run([“ls”, “-l”])
# 获取命令输出
result = subprocess.run([“echo”, “Hello World”],
capture_output=True, text=True)
print(result.stdout) # 输出: Hello World
Popen类(高级控制)
提供更精细的控制,适合复杂场景。
可以实时交互(发送输入/获取输出),不等待命令完成。
import subprocess
# 启动进程并实时交互
proc = subprocess.Popen([“python”],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
text=True)
# 发送命令并获取输出
proc.stdin.write(“print(‘Hello!’)\n”)
proc.stdin.flush()
output = proc.stdout.readline()
print(output) # 输出: Hello!
# 启动进程并实时交互
proc = subprocess.Popen([“python”],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
text=True)
# 发送命令并获取输出
proc.stdin.write(“print(‘Hello!’)\n”)
proc.stdin.flush()
output = proc.stdout.readline()
print(output) # 输出: Hello!
关键参数详解(大白话版)
1. args – 要执行的命令
可以是字符串或列表。推荐使用列表更安全:
# 不推荐(有风险)
subprocess.run(“ls -l”, shell=True)
# 推荐方式
subprocess.run([“ls”, “-l”])
subprocess.run(“ls -l”, shell=True)
# 推荐方式
subprocess.run([“ls”, “-l”])
2. capture_output – 捕获输出
设为True
时,可以获取命令的输出结果(否则输出会直接显示在终端)。
3. text – 文本模式
设为True
时,输入/输出会被当作字符串处理(否则是字节数据)。
4. stdin, stdout, stderr – 标准输入输出
控制命令的输入来源和输出位置:
subprocess.PIPE
– 创建管道用于Python交互subprocess.DEVNULL
– 丢弃输出- 文件对象 – 输出到文件
5. shell – 谨慎使用!
警告:除非必要,否则避免使用shell=True
!
它可能带来安全风险(命令注入攻击),而且在不同系统上行为可能不同。
6. timeout – 超时设置
设置命令执行的最长时间(秒),超时后会抛出异常:
try:
subprocess.run([“ping”, “google.com”], timeout=5)
except subprocess.TimeoutExpired:
print(“命令执行超时!”)
subprocess.run([“ping”, “google.com”], timeout=5)
except subprocess.TimeoutExpired:
print(“命令执行超时!”)
实际应用场景
场景1:获取系统信息
# Windows: 获取IP配置
result = subprocess.run([“ipconfig”], capture_output=True, text=True)
print(result.stdout)
# Linux/Mac: 获取磁盘空间
result = subprocess.run([“df”, “-h”], capture_output=True, text=True)
print(result.stdout)
result = subprocess.run([“ipconfig”], capture_output=True, text=True)
print(result.stdout)
# Linux/Mac: 获取磁盘空间
result = subprocess.run([“df”, “-h”], capture_output=True, text=True)
print(result.stdout)
场景2:运行Python脚本
# 运行另一个Python脚本
subprocess.run([“python”, “other_script.py”])
# 带参数运行
subprocess.run([“python”, “process_data.py”, “input.csv”, “output.csv”])
subprocess.run([“python”, “other_script.py”])
# 带参数运行
subprocess.run([“python”, “process_data.py”, “input.csv”, “output.csv”])
场景3:文件操作
# 解压文件(Linux/Mac)
subprocess.run([“tar”, “xvf”, “archive.tar.gz”])
# 复制文件(Windows)
subprocess.run([“copy”, “file1.txt”, “file2.txt”], shell=True)
subprocess.run([“tar”, “xvf”, “archive.tar.gz”])
# 复制文件(Windows)
subprocess.run([“copy”, “file1.txt”, “file2.txt”], shell=True)
常见错误与处理
1. FileNotFoundError
命令或程序不存在时发生:
try:
subprocess.run([“wrong_command”])
except FileNotFoundError as e:
print(f”命令不存在: {e}”)
subprocess.run([“wrong_command”])
except FileNotFoundError as e:
print(f”命令不存在: {e}”)
2. CalledProcessError
命令返回非零状态码(执行失败):
try:
subprocess.run([“git”, “wrong_command”], check=True)
except subprocess.CalledProcessError as e:
print(f”命令执行失败,状态码: {e.returncode}”)
subprocess.run([“git”, “wrong_command”], check=True)
except subprocess.CalledProcessError as e:
print(f”命令执行失败,状态码: {e.returncode}”)
3. TimeoutExpired
命令执行超时:
try:
subprocess.run([“long_running_task”], timeout=30)
except subprocess.TimeoutExpired:
print(“命令执行超时”)
subprocess.run([“long_running_task”], timeout=30)
except subprocess.TimeoutExpired:
print(“命令执行超时”)
安全注意事项
重要安全原则:永远不要信任用户输入!
当使用subprocess运行命令时,如果命令中包含用户提供的数据,必须非常小心:
# 危险示例(不要这样做!)
user_input = input(“请输入文件名: “)
subprocess.run(f”rm {user_input}”, shell=True) # 用户可能输入恶意命令
user_input = input(“请输入文件名: “)
subprocess.run(f”rm {user_input}”, shell=True) # 用户可能输入恶意命令
安全做法:
# 安全方式
user_input = “some_file.txt” # 假设来自用户
subprocess.run([“rm”, user_input]) # 使用列表形式,不调用shell
user_input = “some_file.txt” # 假设来自用户
subprocess.run([“rm”, user_input]) # 使用列表形式,不调用shell
使用列表形式传递参数可以避免大多数命令注入风险。