在 Python 中执行 Windows 命令有多种方法,最常用的是 subprocess 模块,下面我将详细介绍几种常用的方法,并提供代码示例和最佳实践。

核心方法:subprocess 模块
subprocess 是 Python 官方推荐的用于创建和管理子进程的模块,功能强大且灵活,它替代了旧的 os.system、os.spawn* 等方法。
subprocess.run() (推荐,Python 3.5+)
这是最现代、最推荐的方法,它会执行命令,并等待其完成,然后返回一个 CompletedProcess 对象。
基本用法
import subprocess
# 执行一个简单的命令,例如列出当前目录的文件
# 注意:命令和参数需要作为一个列表传递
result = subprocess.run(['dir'], capture_output=True, text=True, shell=True)
# 检查命令是否执行成功
if result.returncode == 0:
print("命令执行成功!")
print("标准输出:")
print(result.stdout)
else:
print("命令执行失败!")
print("标准错误:")
print(result.stderr)
参数详解
['dir']: 要执行的命令列表。dir是一个 Windows 内部命令。capture_output=True: 捕获标准输出和标准错误,你也可以使用stdout=subprocess.PIPE和stderr=subprocess.PIPE来分别指定。text=True: 将捕获的输出解码为文本字符串(默认为字节流),你也可以使用universal_newlines=True,它们是等价的。shell=True: 通过系统的命令行解释器(如cmd.exe)来执行命令,这允许你使用 shell 特有的功能,比如管道 ()、通配符 () 等,但同时也带来了安全风险(如果命令字符串来自不可信的输入),对于简单的命令,shell=True很方便。check=True: 如果设置此参数,并且命令的返回码(exit code)不为 0,则会抛出subprocess.CalledProcessError异常。
使用 shell=True 的更简洁写法
当使用 shell=True 时,你可以直接传递一个字符串作为命令,而不是列表。
import subprocess
# 使用字符串,可以方便地使用 shell 特性
command = "dir /b" # /b 参数表示只列出文件名,不包含额外信息
result = subprocess.run(command, capture_output=True, text=True, shell=True)
if result.returncode == 0:
print("命令执行成功!")
print(result.stdout)
else:
print(f"命令执行失败,返回码: {result.returncode}")
print(result.stderr)
subprocess.Popen() (最灵活)
Popen (process open) 是一个更底层的类,它不会等待命令执行完成,而是立即返回一个 Popen 对象,你需要手动管理进程的生命周期,这对于需要与进程进行实时交互(向进程发送输入或实时读取输出)的场景非常有用。

基本用法
import subprocess
# 创建一个子进程
# 注意:这里我们使用列表形式,并且不需要 shell=True 来执行简单的 dir 命令
# 但 dir 是一个内部命令,所以通常还是需要 shell=True
process = subprocess.Popen(['cmd', '/c', 'dir'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
# 等待进程结束并获取输出
stdout, stderr = process.communicate()
print(f"返回码: {process.returncode}")
if process.returncode == 0:
print("标准输出:")
print(stdout)
else:
print("标准错误:")
print(stderr)
Popen 的优势:实时交互
import subprocess
# 启动一个交互式命令,ping
# shell=True 让我们可以直接使用 'ping' 命令
process = subprocess.Popen('ping www.google.com', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
# 实时打印输出
for line in process.stdout:
print(line, end='') # end='' 因为 line 中已经包含了换行符
# 等待进程结束
process.wait()
print(f"\nPing 命令结束,返回码: {process.returncode}")
os.system() (不推荐,仅作了解)
这是最古老、最简单的方法,但功能有限,不推荐在新代码中使用,它执行命令,并打印输出到终端,但很难捕获输出。
import os
# os.system 会直接在控制台打印 dir 的结果
# 返回的是命令执行后的退出码
return_code = os.system('dir')
print(f"\n命令执行完毕,返回码: {return_code}")
为什么不推荐?
- 无法捕获输出:无法将命令的输出作为字符串获取,只能在控制台看到。
- 安全性差:容易受到 shell 注入攻击。
- 功能弱:无法进行复杂的进程控制。
os.popen() (不推荐,仅作了解)
os.popen 可以打开一个管道,允许你读取命令的输出或向命令写入输入,它比 os.system 稍好,但仍然不如 subprocess 灵活和安全。
import os
# 打开一个管道来读取 'dir' 命令的输出
# 返回一个文件对象,可以像读取文件一样读取
with os.popen('dir /b') as pipe:
output = pipe.read()
print("通过 os.popen 获取的输出:")
print(output)
总结与最佳实践
| 方法 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
subprocess.run() |
现代、推荐、安全、功能全面 | 相对较新 (Python 3.5+) | 绝大多数情况下的首选。 |
subprocess.Popen() |
最灵活,支持实时交互和复杂进程管理 | 代码更复杂,需要手动管理进程 | 需要与子进程进行持续交互时(如 SSH 客户端、游戏服务器)。 |
os.system() |
极其简单 | 无法捕获输出,不安全,功能弱 | 快速执行一个命令且不关心输出时(不推荐)。 |
os.popen() |
可以捕获输出 | 已被 subprocess 淘汰,功能有限 |
维护非常旧的 Python 代码时。 |
最佳实践建议
- 首选
subprocess.run():对于绝大多数执行 Windows 命令的需求,subprocess.run()是最佳选择。 - 何时使用
shell=True:- 当你的命令是单个字符串,并且需要使用*管道 ()、重定向 (
>,<) 或通配符 (``)** 等 shell 特性时。 - 安全警告:如果命令的任何部分来自用户输入,绝对不要使用
shell=True,因为这可能导致命令注入攻击,如果必须使用,请务必对输入进行严格的清理和验证。
- 当你的命令是单个字符串,并且需要使用*管道 ()、重定向 (
- 何时使用
shell=False(默认):- 当你将命令和参数作为列表传递时,这是更安全的方式,Python 会直接执行程序,而不经过 shell 解释。
- 执行一个外部程序如
python.exe:subprocess.run(['python', 'my_script.py'])。
一个综合示例
import subprocess
import time
def run_command(command, use_shell=False):
"""
执行一个命令并打印其结果。
:param command: 命令字符串或列表。
:param use_shell: 是否使用 shell 解释器。
"""
print(f"--- 执行命令: {' '.join(command) if isinstance(command, list) else command} ---")
try:
# 使用 check=True 会在命令失败时抛出异常
result = subprocess.run(
command,
capture_output=True,
text=True,
shell=use_shell,
check=True,
encoding='gbk', # 在中文Windows系统上,很多命令的输出是GBK编码,指定可以避免乱码
errors='ignore' # 如果解码失败,忽略错误字符
)
print("标准输出:")
print(result.stdout)
except subprocess.CalledProcessError as e:
print(f"命令执行失败,返回码: {e.returncode}")
print("标准错误:")
print(e.stderr)
except FileNotFoundError:
print(f"错误: 找不到命令或程序,请检查路径是否正确。")
except Exception as e:
print(f"发生未知错误: {e}")
finally:
print("--- 命令执行结束 ---\n")
# 示例1: 使用列表执行,更安全
run_command(['ping', '-n', '4', '127.0.0.1'], use_shell=False)
# 示例2: 使用字符串和 shell=True,方便使用管道
run_command('dir /b | findstr "py"', use_shell=True)
# 示例3: 执行一个不存在的命令
run_command(['non_existent_command'], use_shell=False)
