HOWTO · Python

如何在 Python 中运行 Bash 命令

本教程演示如何在 Python 中运行 bash 命令,重点介绍 Git 命令。学习最佳方法,包括 subprocess 和 os.system,以有效地执行命令。通过实用的示例和清晰的解释改进你的工作流程。非常适合希望自动化任务并简化流程的开发人员。

本页内容

Python 可以启动命令行程序和 shell 命令,用于创建目录或使用 Git 等任务。对于会结束的命令,subprocess.run() 通常是最佳起点:它可以捕获输出和错误,并提供返回码。对于不需要捕获输出的简单情况,使用 os.system();当你需要在进程运行期间与它交互时,选择 subprocess.Popen()。

用 subprocess.run() 运行命令

传入一个参数序列,直接调用可执行文件。这样可以避免让 shell 解析命令。示例使用正在运行的 Python 解释器,因此不依赖 Git 是否已安装,也不依赖特定的 shell。

import subprocess
import sys

result = subprocess.run(
    [sys.executable, "-c", "print('Hello from Python')"],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
)

print("stdout:", result.stdout)
print("stderr:", result.stderr)
print("return code:", result.returncode)
stdout: b'Hello from Python\n'
stderr: b''
return code: 0

这里的 stdout 和 stderr 是字节,returncode 是整数。返回码 0 按惯例表示成功;非零值表示程序报告了问题。你可以自己检查它,也可以传入 check=True,让 run() 在返回码非零时引发 CalledProcessError。例如,要运行 Git,传入 ['git', 'status'] 这样的参数列表;它的输出取决于仓库,应作为数据处理,不要假定它有固定内容。

调用程序并不自动等于 Bash 命令。管道、重定向或 && 等 shell 语法需要 shell。设置 shell=True 是让 Python 使用平台 shell;它并不保证是 Bash。避免把不可信的输入插值到 shell 命令中,因为这可能导致命令注入。

用 os.system() 运行 shell 命令

os.system() 是针对简单命令的一个受限选项,适用于你不需要捕获其输出或详细处理错误时。例如,os.system("mkdir reports") 让平台 shell 运行创建目录的命令。命令会写入继承的控制台流。该函数返回的是状态值,而不是命令的普通输出;对该状态的解释可能因平台而异。当你需要一致地检查捕获的输出、错误或返回码时,优先使用 subprocess.run()。

对进行中的进程使用 subprocess.Popen()

当程序在结束前需要输入或其他交互时,使用 subprocess.Popen()。它启动进程,并给你的代码提供一个可操作的过程对象。对于输出有界的进程,设置 stdout=subprocess.PIPE 和 stderr=subprocess.PIPE,然后调用 communicate() 读取这些流并等待完成。返回的流值是字节,除非你另行安排解码。

communicate() 适用于进程会结束且其捕获的输出可以放进内存的情况。它不是用于无界输出的流式方法。communicate() 完成后,进程已经结束;无需再对它调用 kill() 或 terminate()。对于只是会结束的普通命令,run() 提供了更简单的接口。

选择正确的方法

大多数命令使用 subprocess.run():传入参数列表,在需要时捕获流,并检查 returncode。仅当简短的 shell 命令就足够且其输出和详细状态不重要时,才使用 os.system()。当你的程序必须管理正在运行的进程或与它交换数据时,使用 Popen()。仅当命令需要 shell 语法时才选择 shell,并让不可信的值远离被插值的 shell 字符串。