在Python中执行DOS命令(在Windows系统中)或Shell命令(在Linux/macOS系统中)是一项常见的需求,特别是在需要与操作系统交互、自动化任务或管理文件时,Python提供了多种方式来实现这一功能,其中最常用的是subprocess模块,它功能强大且灵活,能够处理命令的输入、输出和错误流。os.system和os.popen也是可选的方法,但它们的功能相对有限,不推荐在新代码中使用。

使用subprocess模块执行命令
subprocess模块是Python 3.5及以上版本中执行系统命令的首选方式,它允许我们启动新进程、连接到它们的输入/输出/错误管道,并获取返回码,以下是subprocess模块的核心函数及其用法:
-
subprocess.run()
这是最推荐的函数,它提供了统一的接口来执行命令并管理其输入、输出和错误流。import subprocess result = subprocess.run(["dir"], shell=True, capture_output=True, text=True) print(result.stdout)
shell=True:允许通过系统Shell执行命令(在Windows中为CMD,在Linux中为Bash)。capture_output=True:捕获命令的标准输出和标准错误。text=True:以文本形式返回输出(默认为字节)。
-
subprocess.Popen()
当需要更细粒度地控制进程时(如实时读取输出),可以使用Popen。process = subprocess.Popen(["ping", "-n", "4", "127.0.0.1"], stdout=subprocess.PIPE, text=True) for line in process.stdout: print(line.strip())stdout=subprocess.PIPE:将标准输出重定向到管道。
-
subprocess.call()和subprocess.check_call()
(图片来源网络,侵删)call():执行命令并返回返回码,但不捕获输出。check_call():如果命令返回非零状态码(表示失败),则抛出异常。
命令执行中的常见参数
以下是subprocess.run()和其他函数中常用参数的说明:
| 参数 | 说明 |
|---|---|
args |
要执行的命令,可以是字符串列表(如["ls", "-l"])或字符串(需shell=True)。 |
shell |
是否通过Shell执行命令(Windows中为CMD,Linux中为Bash)。 |
cwd |
设置命令执行的工作目录。 |
timeout |
命令执行的超时时间(秒),超时后抛出subprocess.TimeoutExpired异常。 |
input |
通过标准输入传递给命令的字符串或字节。 |
stdout |
指定标准输出的处理方式(如subprocess.PIPE表示捕获)。 |
stderr |
指定标准错误的处理方式(如subprocess.STDOUT表示合并到标准输出)。 |
错误处理和最佳实践
执行系统命令时,错误处理至关重要,如果命令不存在或返回错误码,应妥善处理异常:
try:
result = subprocess.run(["nonexistent_command"], shell=True, check=True)
except subprocess.CalledProcessError as e:
print(f"命令执行失败,返回码: {e.returncode}")
except FileNotFoundError:
print("命令不存在")
替代方法:os.system和os.popen
os.system():简单直接,但无法获取命令输出,仅返回退出码。os.system("dir") # 直接在终端显示输出os.popen():可以读取命令输出,但已被subprocess取代,不推荐使用。
相关问答FAQs
Q1: 如何在Python中执行带空格的DOS命令?
A: 如果命令路径或参数包含空格,建议将命令作为字符串传递并设置shell=True,
subprocess.run('"C:\Program Files\MyApp\app.exe" /option', shell=True)
注意:Windows中需用双引号包裹路径,而Linux中需用单引号或转义空格。

Q2: 如何在Python中实时获取DOS命令的输出?
A: 使用subprocess.Popen结合stdout=subprocess.PIPE,并逐行读取输出流:
process = subprocess.Popen(["ping", "-n", "4", "127.0.0.1"], stdout=subprocess.PIPE, text=True)
for line in process.stdout:
print(line.strip()) # 实时打印每一行输出
这样可以避免subprocess.run()的阻塞问题,适用于长时间运行的命令。
