os.system vs. subprocess
os.system: 这是一个比较老、简单直接的方法,它会启动一个新的shell(在Linux/macOS上是/bin/sh,在Windows上是cmd.exe)来执行你的命令,执行完后,你的Python脚本会继续往下运行。缺点是,它无法获取到被调用脚本的输出结果,也难以进行复杂的错误处理。subprocess: 这是现代Python官方推荐的模块,它提供了更强大、更灵活、更安全的方式来创建子进程,你可以控制输入、输出、错误流,检查返回码,并且可以避免os.system可能带来的shell注入风险。
使用 os.system() (简单但不推荐)
这是最简单的方法,适用于你只是想运行一个脚本,不关心它的输出和返回结果。

import os
# 假设你有一个名为 other_script.py 的脚本
script_path = 'other_script.py'
print(f"准备使用 os.system 运行 {script_path}...")
# 返回值是脚本的退出状态码 (0表示成功,非0表示失败)
exit_code = os.system(script_path)
print(f"脚本执行完毕,退出码: {exit_code}")
other_script.py 的内容 (用于测试):
# other_script.py
import time
print("这是另一个Python脚本,它正在运行...")
time.sleep(2)
print("它执行完了!")
如何运行: 将两个文件放在同一个目录下,然后运行主脚本。
python main_script.py
输出:
准备使用 os.system 运行 other_script.py...
这是另一个Python脚本,它正在运行...
它执行完了!
脚本执行完毕,退出码: 0
缺点:

- 无法获取输出: 你无法在主脚本中捕获
other_script.py打印的"这是另一个Python脚本..."。 - 安全风险: 如果
script_path变量来自不可信的输入,可能会被恶意利用(script_path = "malicious_command; rm -rf /")。
使用 subprocess 模块 (强烈推荐)
subprocess是更现代、更强大的选择。
subprocess.run() (最常用,Python 3.5+)
这是subprocess模块的推荐接口,功能全面且易于使用。
场景A:执行一个Python脚本,并捕获其标准输出
import subprocess
script_path = 'other_script.py'
print(f"准备使用 subprocess.run 运行 {script_path}...")
# 使用 check=True 会在脚本返回非0退出码时抛出 CalledProcessError 异常
# text=True 会将输出解码为文本
# capture_output=True 会捕获标准输出和标准错误
try:
result = subprocess.run(
['python', script_path], # 将命令和参数作为列表传递,更安全
check=True,
capture_output=True,
text=True,
encoding='utf-8' # 明确指定编码
)
# result.stdout 是脚本的输出
print("脚本执行成功!")
print("捕获到的标准输出:")
print(result.stdout)
# result.stderr 是脚本的标准错误输出
if result.stderr:
print("捕获到的标准错误:")
print(result.stderr)
# result.returncode 是脚本的退出码
print(f"退出码: {result.returncode}")
except subprocess.CalledProcessError as e:
print(f"脚本执行失败,返回码: {e.returncode}")
print(f"标准输出: {e.stdout}")
print(f"标准错误: {e.stderr}")
输出:

准备使用 subprocess.run 运行 other_script.py...
脚本执行成功!
捕获到的标准输出:
这是另一个Python脚本,它正在运行...
它执行完了!
退出码: 0
场景B:直接执行Python代码字符串
如果你想执行一段Python代码,而不是一个文件,可以使用-c选项。
import subprocess
code_to_run = "print('Hello from inline code!'); import datetime; print(f'Time: {datetime.datetime.now()}')"
print(f"准备执行代码: {code_to_run}")
# 注意命令需要是一个列表
command = ['python', '-c', code_to_run]
result = subprocess.run(command, capture_output=True, text=True, check=True)
print("\n执行结果:")
print(result.stdout)
输出:
准备执行代码: print('Hello from inline code!'); import datetime; print(f'Time: {datetime.datetime.now()}')
执行结果:
Hello from inline code!
Time: 2025-10-27 10:30:00.123456
subprocess.Popen() (更底层,更灵活)
当你需要与子进程进行更复杂的交互时(持续发送输入或实时读取输出),Popen是更好的选择,它不会像run那样等待命令执行完成。
import subprocess
script_path = 'other_script.py'
print("准备使用 subprocess.Popen 运行脚本...")
# 启动进程,但不等待
process = subprocess.Popen(
['python', script_path],
stdout=subprocess.PIPE, # 捕获标准输出
stderr=subprocess.PIPE, # 捕获标准错误
text=True,
encoding='utf-8'
)
# 可以在这里做其他事情...
# 等待进程结束,并获取输出
stdout, stderr = process.communicate()
print("\n--- Popen 执行结果 ---")
print("标准输出:")
print(stdout)
if stderr:
print("标准错误:")
print(stderr)
print(f"退出码: {process.returncode}")
总结与最佳实践
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
os.system() |
简单、一行代码搞定 | 无法获取输出、不安全、功能有限 | 快速执行简单命令,不关心结果 |
subprocess.run() |
强烈推荐、功能强大、安全、可获取输出和错误码、可控制超时 | 相对os.system代码稍多 |
绝大多数场景,特别是需要获取脚本输出或进行错误处理时 |
subprocess.Popen() |
最灵活,可进行复杂交互(如实时通信) | 代码更复杂,需要手动管理进程生命周期 | 需要与子进程持续交互,或构建复杂的管道命令时 |
最终建议:
- 永远优先使用
subprocess.run(),它提供了os.system的所有优点,同时弥补了它的所有缺点。 - 将命令和参数作为列表传递给
subprocess.run(['python', 'script.py']),而不是字符串,这样可以有效防止shell注入攻击。 - 使用
capture_output=True和text=True来方便地处理文本输出。 - 使用
check=True来自动处理脚本执行失败的情况,它会为你抛出异常。 - 如果只是想运行一个命令且不关心其结果,
os.system虽然简单,但为了代码的健壮性和可维护性,仍然推荐使用subprocess.run(..., check=False)。
