Python 中如何执行外部程序或系统命令?
Python 执行系统命令推荐 subprocess.run()(便于控制参数、输出和返回码),注意 shell 与选项注入;os.system() 仍可用但能力较少。本文介绍 subprocess.run 的用法、获取输出和安全注意事项。
推荐用 subprocess.run(['命令', '参数1', ...])——这是官方推荐的现代接口,参数以列表传递,在不经过 shell 时可避免 shell 元字符被解释,但仍需防止目标命令的选项注入,还能方便地捕获输出和返回码。老的 os.system() 已不推荐。
基本用法
import subprocess
subprocess.run(['ls', '-la'])
列表第一个元素是程序名,其余是参数。
捕获输出与返回码
result = subprocess.run(['ls', '-la'], capture_output=True, text=True)
print(result.stdout) # 标准输出(字符串)
print(result.returncode) # 退出码,0 表示成功
capture_output=True:捕获 stdout 和 stderr;text=True:以字符串而非字节返回;check=True:命令失败(返回码非 0)时抛CalledProcessError。
为什么不推荐 os.system()
os.system('ls -la') # 输出直接打到终端,拿不到结果;只返回退出状态
缺点:无法捕获输出、参数拼接容易引入 shell 注入风险、官方文档明确建议用 subprocess 替代。
安全提示
不要用 shell=True 拼接用户输入:
# 危险!
subprocess.run(f'cat {user_input}', shell=True)
# 不经 shell;此 cat 支持 --,用于终止选项解析
subprocess.run(['cat', '--', user_input], check=True)
Windows 上 .bat/.cmd 可能由系统通过 shell 启动,即使 shell=False 也不能一概保证无 shell 解析;不可信参数应按平台官方说明处理。os.system 仍可用,并未被移除。
常见问题(FAQ)
Q:命令执行很久会卡住吗?
A:run() 是阻塞的,可以加 timeout=秒数,超时抛 TimeoutExpired;需要异步并行用 subprocess.Popen。
Q:Windows 和 Linux 通用吗?
A:subprocess 本身跨平台,但命令名和参数因系统而异;shell=True 下 Windows 走 cmd,Linux 走 /bin/sh。
Q:如何执行带管道、重定向的命令?
A:管道建议在 Python 里串多个 subprocess(一个的输出接另一个的输入);重定向用 stdout=open('f', 'w')。实在需要 shell 特性才考虑 shell=True。