Python进阶教程:27_subprocess 模块 零基础超详细教程

subprocess 是 Python 内置的子进程管理标准库 ,核心作用是在 Python 代码中调用外部系统命令、启动其他程序 / 脚本,并能控制它们的输入输出、获取执行结果、监控运行状态。 简单说:你可以在 Python 程序里,直接执行 cmd / 终端命令、运行其他 exe 程序、调用别的脚本,就像你手动在命令行里操作一样,全程由代码自动完成。

它替代了老旧的 os.systemos.popen 等工具,功能更强大、控制更精细,是写自动化脚本、批量处理、工具调用的必备模块。

本文从基础概念、核心函数到实战场景、避坑指南,全程配可运行代码 + 逐行解释,零基础也能完全吃透。


一、前置基础概念

1. 通俗理解

你可以把当前运行的 Python 程序理解成「主办公室」:

  • subprocess 就是帮你出去跑腿的员工,可以帮你启动别的程序(比如打开记事本、执行 cmd 命令、运行另一个 Python 脚本)
  • 这些被启动的程序叫「子进程」,和主程序独立运行,你可以让它跑完等结果,也可以让它在后台自己跑
  • 你能拿到它的输出、判断它有没有执行成功、甚至给它传输入内容

2. 能做什么?

  • 执行系统命令:比如 Windows 的 dirping,Mac/Linux 的 lsps
  • 调用第三方工具:比如调用 gitffmpeg、压缩解压工具
  • 运行其他脚本 / 程序:比如在 Python 里调用另一个 Python 脚本、exe 程序
  • 自动化批量操作:比如批量执行命令、批量处理文件
  • 获取命令输出:把命令执行的结果拿回来,在 Python 里继续处理

3. 模块说明

  • 内置标准库:不需要安装,直接 import subprocess 即可使用
  • 推荐核心函数:Python 3.5+ 统一推荐用 subprocess.run(),覆盖 90% 日常场景
  • 进阶复杂场景用 subprocess.Popen,实现后台运行、实时交互等高级功能

二、入门核心:subprocess.run ()

subprocess.run() 是最基础、最常用的函数,作用是执行指定命令,等待命令执行完毕后,返回执行结果

1. 第一个最简单的例子

先执行一条最简单的 echo 命令,直观感受用法:

python 复制代码
import subprocess

# 执行命令:echo 你好,Python
# Windows 系统需要加 shell=True,因为 echo 是 cmd 内置命令
result = subprocess.run(["echo", "你好,Python"], shell=True, text=True)

print("命令执行完毕")
逐行解释
  1. subprocess.run():启动子进程执行命令,会阻塞等待命令执行完,才继续往下走
  2. 第一个参数 ["echo", "你好,Python"]:要执行的命令,用列表形式拆分「命令 + 参数」,是最推荐的安全写法
  3. shell=True:表示用系统的命令解释器(cmd /bash)来执行命令。系统内置命令(echo、dir、cd 等)必须加这个参数,否则会找不到命令
  4. text=True:让输入输出都用字符串格式,不然默认返回的是 bytes 字节,中文会乱码

💡 系统差异说明:

  • Windows:内置命令(dir、echo、cd)需要 shell=True;独立程序(python、git)可以不用
  • Mac/Linux:ls、pwd 等大多是独立程序,一般不用 shell=True

2. 返回值:CompletedProcess 对象

run() 执行完会返回一个 CompletedProcess 对象,里面包含了命令执行的所有结果,最常用三个属性:

属性 含义 说明
.returncode 退出状态码 0 表示执行成功,非 0 表示执行失败 / 出错
.stdout 标准输出内容 命令正常打印的结果
.stderr 标准错误输出 命令报错时的错误信息
示例:获取命令执行结果
python 复制代码
import subprocess

# 执行 python --version 命令,捕获输出
# capture_output=True:把命令的输出捕获下来,存在stdout/stderr里
result = subprocess.run(
    ["python", "--version"],
    capture_output=True,
    text=True
)

print("是否成功:", result.returncode == 0)
print("正常输出:", result.stdout)
print("错误输出:", result.stderr)

运行结果示例:

python 复制代码
是否成功: True
正常输出: Python 3.11.4

错误输出: 
关键参数解释
  • capture_output=True:捕获命令的标准输出和错误输出,不然输出会直接打印到控制台,拿不到内容
  • 如果你只需要标准输出,也可以单独写 stdout=subprocess.PIPE,和 capture_output=True 效果类似

三、最常用参数详解

subprocess.run() 有很多参数,新手掌握下面 7 个就能应对绝大多数场景:

参数 作用 新手使用建议
args 要执行的命令,推荐用列表形式 ["命令", "参数1", "参数2"] 优先用列表,安全可控
shell 是否用系统 shell 执行命令 内置命令加 True,外部程序尽量不加
capture_output 是否捕获输出(stdout+stderr) 需要拿结果就加 True
text 是否用字符串模式(默认是 bytes) 建议一律加 True,避免乱码
encoding 指定编码,比如 gbkutf-8 Windows 中文乱码时指定 gbk
check 命令失败(returncode≠0)时自动抛异常 需要严格校验成功与否时加 True
timeout 超时时间,单位秒,超时自动终止命令 防止命令卡死

下面逐个演示常用场景。


四、常用场景实战(带完整例子 + 解释)

场景 1:执行命令并捕获输出

这是最常用的场景:执行命令,把输出拿回来在 Python 里处理。

示例:执行 ping 命令检测网络
python 复制代码
import subprocess

# Windows 下 ping 4 次百度
# -n 4 表示发送4个包,Windows是-n,Mac/Linux是-c
result = subprocess.run(
    ["ping", "-n", "4", "www.baidu.com"],
    capture_output=True,
    text=True,
    encoding="gbk"  # Windows cmd 默认是gbk编码,指定后中文不会乱码
)

print("执行结果:")
print(result.stdout)

if result.returncode == 0:
    print("✅ 网络通畅")
else:
    print("❌ 网络不通")
解释
  • encoding="gbk":Windows 命令行默认用 GBK 编码,不加的话中文会变成乱码,这是新手高频踩坑点
  • Mac/Linux 一般默认是 UTF-8,不用额外指定

场景 2:命令失败自动报错(check 参数)

默认情况下,哪怕命令执行失败,Python 也不会报错,只会把错误信息存在 stderr 里。 加 check=True 后,只要命令返回非 0 状态码,就会直接抛出 CalledProcessError 异常,适合严格校验的场景。

python 复制代码
import subprocess

try:
    # 执行一个不存在的命令,加check=True会自动报错
    subprocess.run(
        ["xxx_not_exist_cmd"],
        check=True,
        capture_output=True,
        text=True
    )
except subprocess.CalledProcessError as e:
    print("命令执行失败!")
    print("错误信息:", e.stderr)

场景 3:给命令传递输入内容(stdin)

有些命令需要用户输入内容(比如交互式程序),可以通过 input 参数直接把内容传进去。

示例:给 Python 解释器传代码执行
python 复制代码
import subprocess

# 要输入的代码
code = """
print("hello from subprocess")
print(1 + 2 + 3)
"""

result = subprocess.run(
    ["python"],
    input=code,  # 把code作为标准输入传给子进程
    capture_output=True,
    text=True
)

print("子进程输出:")
print(result.stdout)

运行结果:

python 复制代码
子进程输出:
hello from subprocess
6

场景 4:设置超时,防止卡死

有些命令可能会卡住(比如死循环、网络超时),加 timeout 参数可以强制终止,避免主程序一直等。

python 复制代码
import subprocess

try:
    # 执行一个会睡10秒的命令,设置超时2秒
    subprocess.run(
        ["python", "-c", "import time; time.sleep(10)"],
        timeout=2
    )
except subprocess.TimeoutExpired:
    print("⏰ 命令超时,已强制终止")

超时后会抛出 TimeoutExpired 异常,子进程会被强制终止。


场景 5:调用另一个 Python 脚本

这是自动化里非常实用的场景:在主程序里调用另一个脚本,还能拿到它的输出。

第一步:先准备一个子脚本 sub_script.py
python 复制代码
# sub_script.py
print("我是子脚本,开始运行")
print("计算结果:", 100 + 200)
第二步:主脚本调用它
python 复制代码
import subprocess

result = subprocess.run(
    ["python", "sub_script.py"],
    capture_output=True,
    text=True
)

print("子脚本输出:")
print(result.stdout)

拓展:还可以通过命令行参数给子脚本传参,配合 sys.argv 接收,实现更灵活的调用。


五、进阶:subprocess.Popen(后台运行 / 实时交互)

subprocess.run() 是「阻塞等待」的:必须等子进程跑完,才会继续往下走。 如果需要启动后台进程、实时读取输出、和进程交互 ,就要用更底层的 subprocess.Popen

1. 什么时候用 Popen?

  • 启动程序后不用等它结束,主程序继续往下跑(比如打开记事本、启动服务)
  • 需要实时逐行读取命令输出
  • 需要和子进程反复交互(输入、输出、再输入)

2. 示例 1:后台启动程序,不阻塞主程序

python 复制代码
import subprocess
import time

# 启动Windows记事本,不等待,主程序继续运行
# Popen 不会阻塞,启动完立刻继续往下执行
proc = subprocess.Popen(["notepad.exe"])

print("记事本已经启动了,主程序继续运行...")
# 主程序可以继续做别的事
for i in range(5):
    print(f"主程序运行中... {i+1}")
    time.sleep(1)

# 可以主动终止子进程
# proc.terminate()

运行后会发现:记事本打开的同时,Python 主程序还在继续打印,不会卡住。


3. 示例 2:实时逐行读取命令输出

run() 是等命令全部跑完才一次性返回所有输出;Popen 可以边运行边读输出,适合长时间运行、有进度输出的命令。

python 复制代码
import subprocess
import sys

# 执行一个逐行输出的命令
proc = subprocess.Popen(
    ["python", "-c", "import time; [print(f'第{i}行', flush=True) or time.sleep(0.5) for i in range(5)]"],
    stdout=subprocess.PIPE,
    text=True
)

# 逐行读取输出,实时打印
print("实时输出:")
for line in proc.stdout:
    print("👉", line.strip())

# 等待进程结束,获取退出码
proc.wait()
print("命令结束,退出码:", proc.returncode)

注意:子进程输出如果有缓冲,可能不会实时打印,一般加 flush=True 强制刷新缓冲区。


六、新手高频踩坑 & 避坑指南

1. 命令到底用列表还是字符串?要不要加 shell=True?

这是新手最容易混乱的点,直接给结论: ✅ 优先用列表形式,不加 shell=True

  • 优点:安全,不会有命令注入风险,参数自动转义
  • 适用:调用独立程序(python、git、ffmpeg 等)

⚠️ 只有系统内置命令才加 shell=True

  • 比如 Windows 的 direchocd,Mac/Linux 的 cd
  • 风险:如果命令里拼接了用户输入的内容,可能被注入恶意命令,有安全风险

❌ 反面教材(有注入风险):

python 复制代码
# 危险!如果用户输入 "; del /f /s /q C:\*",就会执行恶意命令
user_input = input("请输入文件名:")
subprocess.run(f"dir {user_input}", shell=True)

✅ 安全写法:

python 复制代码
# 用列表传参,自动转义,不会被注入
user_input = input("请输入文件名:")
subprocess.run(["dir", user_input], shell=True)

2. 输出是乱码 /bytes 看不懂

  • 原因:默认 stdout/stderr 是 bytes 类型
  • 解决:加 text=True 参数,自动转成字符串
  • Windows 中文还是乱码:加 encoding="gbk",因为 cmd 默认是 GBK 编码

3. 提示「不是内部或外部命令」

两种原因:

  1. 命令是系统内置命令,没加 shell=True → 加上即可
  2. 程序没有安装,或者不在系统环境变量里 → 写程序的完整路径,或者配置环境变量

4. 以为 cd 命令能切换主程序目录

subprocess 里执行 cd 命令,只会改变子进程的工作目录,不会影响当前 Python 主程序的目录 。 如果要指定子进程的工作目录,用 cwd 参数:

python 复制代码
# 在指定文件夹里执行命令
subprocess.run(["dir"], shell=True, cwd="C:/Users/xxx/Desktop")

5. 命令一直卡住不结束

  • 大概率是子进程在等输入,或者陷入死循环
  • 解决:加 timeout 参数设置超时,或者检查命令是否需要交互输入

七、安全重要提醒

  1. 永远不要把不可信的用户输入拼进 shell 命令里 ,尤其是加了 shell=True 的时候,会导致命令注入漏洞。
  2. 优先用列表形式传参,让 subprocess 自动处理转义,安全系数高很多。
  3. 执行外部命令前,尽量校验参数合法性。
相关推荐
兄弟加油,别颓废了。41 分钟前
bugku题目
开发语言·前端·python
新网企兴42 分钟前
2026西安GEO推广选哪家?新网企兴帮您精准获客
人工智能·python
zh_xuan1 小时前
c++ string_view
开发语言·c++
阿里嘎多学长1 小时前
2026-09-05 GitHub 热点项目精选
开发语言·程序员·github·代码托管
古少侠1 小时前
用 DS随心转 把 AI 画的 Mermaid 流程图转成 Word 里的高清图
开发语言·c#·word
2601_962297481 小时前
一、Python GUI 的十字路口:免费凑活还是付费破局
python·gui·tkinter·customtkinter·bravurasdk
万年咸鱼1 小时前
Java BufferedOutputStream 详解:原理、用法与性能优化
java·开发语言·性能优化
万年咸鱼1 小时前
Java BufferedInputStream 详解:原理、用法与实战
java·开发语言·python
my05921 小时前
跳出单一信息工具局限:奥米豆构建认知与心智并行的学习范式
大数据·人工智能·python·学习