版权信息
warning
本文章为博主原创文章。遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
写 Python 脚本时,经常会需要在 Python 代码里悄悄跑一个终端命令(比如跑一段 bash 脚本)。
那就不得不提到 Python 官方推荐的现代解决方案:subprocess 模块。由于我只是偶尔写点小脚本,只要掌握其中的一个函数就足够了,在此记录以防忘记。
唯一真神:subprocess.run()
自 Python 3.5 起,官方强烈建议使用 subprocess.run() 来替代其他老旧的函数。它的逻辑非常直白:运行指定的命令,等待它完成,然后返回一个包含执行结果的对象。
我们需要先导入它:
import subprocess
下面我们通过三个最常见的场景,来看看它到底怎么用。
场景一:只管执行,不需要获取输出 (Fire and Forget)
假设你只想在脚本里新建一个文件夹,不需要关心终端打印了什么。
import subprocess
# 执行命令: mkdir new_folder
subprocess.run(["mkdir", "new_folder"])
print("文件夹创建完毕!")
我们把命令写成了一个列表
["mkdir", "new_folder"],而不是一个长字符串"mkdir new_folder"。 这是subprocess的推荐写法,它可以有效避免复杂的空格转义和安全漏洞(比如 Shell 注入)。第一个元素是命令,后面的元素是参数。
场景二:我需要拿到命令的输出内容
这是写脚本时最常见的需求。比如你想用 Python 获取当前的系统时间或者某个配置项的值,你需要把终端打印的字存到 Python 的变量里。
import subprocess
# 运行 echo 命令,并捕获输出
result = subprocess.run(["echo", "Hello from terminal!"], capture_output=True, text=True)
# 打印获取到的内容
print(f"终端说: {result.stdout}")
核心要点: 这里加了两个非常关键的参数:
-
capture_output=True:告诉 Python,不要把结果打印到屏幕上,而是偷偷拦截下来存进
result对象里。 -
text=True:告诉 Python 将输出结果作为普通的 字符串(String) 处理。如果不加这个参数,你得到的是带有
b'...'前缀的字节流(Bytes),处理起来会很麻烦。
场景三:如果命令执行失败了怎么办?
写脚本最怕的就是静默失败。如果外部命令报错了,Python 脚本默认还会继续往下跑,这可能会导致灾难性的后果。
subprocess.run() 返回的 result 对象里,有一个叫 returncode 的属性。returncode == 0 代表成功,非 0 代表出错。
温和的处理方式(手动检查):
import subprocess
result = subprocess.run(["ls", "/nonexistent_folder"], capture_output=True, text=True)
if result.returncode == 0:
print("命令执行成功!")
else:
print(f"糟糕,出错了!错误代码: {result.returncode}")
print(f"错误信息: {result.stderr}") # 报错信息通常存放在 stderr 中
暴力的处理方式(直接让脚本崩溃报错):
如果你希望外部命令一旦失败,Python 脚本就立刻停止并抛出异常,只需加一个 check=True 参数:
import subprocess
# 如果这个命令失败,Python 会直接抛出 CalledProcessError 异常
subprocess.run(["ls", "/nonexistent_folder"], check=True)
总结
如果偶尔写写脚本,把下面这段代码存成代码片段(Snippet),遇到需要调用外部命令的时候直接复制粘贴修改即可:
import subprocess
def run_command(cmd_list):
"""
运行外部命令的通用模板
"""
try:
# capture_output 捕获输出, text=True 返回字符串, check=True 失败时抛出异常
result = subprocess.run(cmd_list, capture_output=True, text=True, check=True)
return result.stdout.strip() # strip() 用来去掉结尾多余的换行符
except subprocess.CalledProcessError as e:
print(f"命令执行失败: {e}")
print(f"错误输出: {e.stderr}")
return None
# 使用示例:
output = run_command(["git", "branch"])
if output:
print(f"当前分支信息:\n{output}")
这就够用了!至于更复杂的管道符(|)交互或者后台异步执行,那是subprocess.Popen 的工作,等到真的需要写复杂的系统脚本时再去了解它也不迟。