【Python】标准库模块subprocess

subprocess 是 Python 中用于创建和管理子进程的标准库模块,可执行外部命令、获取输出、管理输入/输出流及错误流。以下是核心用法详解:


1. 基础命令执行

(1) 同步执行 - subprocess.run()(推荐)
import subprocess

# 执行命令并等待完成(返回 CompletedProcess 对象)
result = subprocess.run(["ls", "-l"], capture_output=True, text=True)

print("返回码:", result.returncode)  # 0 表示成功
print("标准输出:", result.stdout)
print("错误输出:", result.stderr)

关键参数:

  • args:命令列表(推荐)或字符串(需 shell=True
  • capture_output=True:捕获输出(相当于设置 stdout=subprocess.PIPE, stderr=subprocess.PIPE
  • text=True:以字符串形式返回输出(默认返回字节)
  • check=True:返回码非零时抛出 CalledProcessError 异常

2. 高级控制 - subprocess.Popen()

用于异步执行或复杂交互:

# 启动进程
process = subprocess.Popen(
    ["ping", "google.com"],
    stdout=subprocess.PIPE,
    text=True
)

# 逐行读取输出
while True:
    line = process.stdout.readline()
    if not line: 
        break
    print(line.strip())

# 等待进程结束
return_code = process.wait()
print("返回码:", return_code)

3. 输入交互

向子进程传递输入:

# 执行 grep 并传递输入文本
result = subprocess.run(
    ["grep", "python"],
    input="hello\npython\nworld",  # 输入数据
    text=True,
    capture_output=True
)
print(result.stdout)  # 输出: "python"

4. 错误处理

(1) 检查返回码(推荐)
try:
    subprocess.run(["invalid_cmd"], check=True, capture_output=True, text=True)
except subprocess.CalledProcessError as e:
    print(f"命令失败!返回码: {e.returncode}")
    print(f"错误输出: {e.stderr}")
(2) 超时控制
try:
    subprocess.run(["sleep", "10"], timeout=5)  # 5秒后终止进程
except subprocess.TimeoutExpired:
    print("命令执行超时!")

5. 安全提示

  • 避免 shell=True:除非必要(如执行 shell 内置命令),否则使用命令列表形式防止注入攻击:
    # 危险!用户输入可能执行恶意命令
    user_input = "malicious_command; rm -rf /"
    subprocess.run(f"echo {user_input}", shell=True)  # 风险!
    
    # 安全方式(使用列表)
    subprocess.run(["echo", user_input])  # user_input 作为普通参数
    

6. 常见用例

(1) 获取命令输出
output = subprocess.check_output(["date", "+%Y-%m-%d"], text=True)
print("当前日期:", output.strip())
(2) 合并标准输出和错误流
result = subprocess.run(
    ["ls", "/nonexistent"],
    stdout=subprocess.PIPE,
    stderr=subprocess.STDOUT,  # 将错误流合并到标准输出
    text=True
)
print("合并输出:", result.stdout)
(3) 后台执行(不阻塞)
# 启动后台进程(不等待)
subprocess.Popen(["notepad.exe"])

print("主程序继续执行...")

7. 跨平台兼容性

  • 路径分隔符:使用 os.path.join 代替硬编码的 /\
  • 命令差异:Windows 和 Linux 命令不同(如 dir vs ls),可用 sys.platform 做判断:
    import sys
    cmd = ["dir"] if sys.platform.startswith("win") else ["ls", "-l"]
    

总结

场景 推荐方法
简单命令同步执行 subprocess.run()
实时流式处理输出 subprocess.Popen() + 循环读取
需要输入交互 input= 参数
严格错误处理 check=True + 异常捕获
超时控制 timeout= 参数

你可能感兴趣的:(Python,python,开发语言)