Python3 subprocess 模块详解

Python 的 subprocess 模块用于创建新进程、连接到它们的输入 / 输出 / 错误管道,并获取它们的返回码。它是 Python 中替代 os.system()os.popen() 等旧有进程管理函数的推荐方式,提供了更强大、更灵活的进程控制能力。

核心功能与常用函数

subprocess 模块的核心是创建子进程,主要通过以下函数实现:

1. subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None)

Python 3.5+ 新增的推荐函数,封装了大多数常见场景,返回一个 CompletedProcess 对象(包含进程执行结果)。
 
  • 关键参数
    • args:要执行的命令,可为字符串(需配合 shell=True)或列表(推荐,避免命令注入风险)。例如:["ls", "-l"] 或 "ls -l"(需 shell=True)。
    • shell:是否通过系统 shell 执行命令。shell=True 时,args 可为字符串(支持管道 |、通配符 * 等 shell 语法),但存在安全风险(如命令注入)。
    • stdout/stderr:子进程的标准输出 / 错误流的处理方式:
      • None(默认):继承父进程的输出(直接打印到控制台)。
      • subprocess.PIPE:捕获输出,可通过 CompletedProcess.stdout 获取。
      • subprocess.STDOUT:将 stderr 合并到 stdout 中。
    • capture_output:等价于 stdout=PIPE, stderr=PIPE(Python 3.7+),方便捕获输出。
    • check:若为 True,当子进程返回码非 0 时,会抛出 subprocess.CalledProcessError 异常。
    • encoding/text:指定编码(如 encoding="utf-8" 或 text=True),使输出为字符串(否则为字节流 bytes)。
    • timeout:设置超时时间(秒),超时会抛出 subprocess.TimeoutExpired 异常。
    • cwd:指定子进程的工作目录。
    • env:设置子进程的环境变量(字典类型,默认继承父进程环境变量)。
  • 返回值CompletedProcess 对象,包含:
    • returncode:子进程返回码(0 表示成功)。
    • stdout:捕获的标准输出(字符串或字节流,取决于 encoding)。
    • stderr:捕获的标准错误(同上)。

2. 其他常用函数(旧版,推荐优先使用 run()

  • subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, ...):类似 run(),但仅返回子进程的返回码(不捕获输出,除非指定 stdout=PIPE)。
  • subprocess.check_call(args, ...):等价于 run(args, check=True),返回码非 0 时抛出异常。
  • subprocess.check_output(args, ...):等价于 run(args, check=True, stdout=PIPE),返回子进程的 stdout 输出(字符串或字节流)。

典型使用场景

场景 1:执行命令并获取返回码 

import subprocess

# 执行 "ls -l" 命令(Linux/Mac),Windows 可替换为 "dir"
result = subprocess.run(["ls", "-l"])
print("返回码:", result.returncode)  # 0 表示成功
 

场景 2:捕获命令输出(stdout/stderr) 

import subprocess

# 捕获 stdout 和 stderr(字符串形式)
result = subprocess.run(
    ["echo", "Hello, subprocess!"],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    encoding="utf-8"
)
print("输出:", result.stdout)  # 输出:Hello, subprocess!
print("错误:", result.stderr)  # 输出:空(无错误)
 

场景 3:使用 shell 语法(管道、通配符等)

import subprocess

# 使用 shell 管道(需 shell=True)
result = subprocess.run(
    "ls -l | grep .py",  # 查找当前目录下的 .py 文件
    shell=True,
    stdout=subprocess.PIPE,
    encoding="utf-8"
)
print("Python 文件:", result.stdout)
 

场景 4:检查命令是否执行成功(自动抛异常)

import subprocess

try:
    # 执行一个不存在的命令,会抛异常
    subprocess.run(
        ["invalid_command"],
        check=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        encoding="utf-8"
    )
except subprocess.CalledProcessError as e:
    print(f"命令执行失败,返回码:{e.returncode}")
    print(f"错误信息:{e.stderr}")
 

场景 5:设置超时时间

import subprocess

try:
    # 执行一个耗时命令(如 sleep 5),设置超时 2 秒
    subprocess.run(
        ["sleep", "5"],  # Linux/Mac 命令,Windows 可替换为 "timeout 5"
        timeout=2
    )
except subprocess.TimeoutExpired:
    print("命令超时!")
 

场景 6:与子进程交互(输入数据)

import subprocess

# 向子进程输入数据(如通过 echo 传递给 grep 过滤)
result = subprocess.run(
    ["grep", "world"],  # 过滤包含 "world" 的行
    input="hello\nworld\npython",  # 输入给子进程的数据
    stdout=subprocess.PIPE,
    encoding="utf-8"
)
print("过滤结果:", result.stdout)  # 输出:world
 

注意事项

  1. 安全风险shell=True 时,若 args 包含用户输入,可能导致命令注入攻击(例如 args = f"ls {user_input}",若用户输入 ; rm -rf / 会执行危险命令)。尽量使用列表形式的 args 并避免 shell=True
  2. 编码问题:若不指定 encodingstdout/stderr 为字节流(bytes),需用 .decode("utf-8") 转换为字符串。
  3. 资源释放:对于长时间运行的子进程,需确保及时释放资源,避免僵尸进程(可通过 communicate() 或等待进程结束处理)。
  4. 跨平台兼容性:不同操作系统的命令不同(如 ls vs dir),需注意适配。
 
subprocess 模块通过灵活的参数配置,几乎能满足所有进程管理需求,是 Python 中处理外部命令的核心工具。

posted on 2025-11-19 10:06  小陶coding  阅读(0)  评论(0)    收藏  举报