Python 调外部命令时,怎样区分启动失败、退出失败和超时

举报
yd_271400591 发表于 2026/11/12 08:59:22 2026/11/12
【摘要】 用四个可直接运行的 Python 示例,区分 subprocess 的启动失败、非零退出和超时,并保留定位问题所需的退出码和输出。

一个定时任务用 Python 调用外部转换工具。早晨只看到一条“执行失败”的日志,却不知道机器上缺少程序、程序已经报错退出,还是它一直在等待。如果把这三种情况都交给同一套重试逻辑,缺少的程序不会自己出现,已经写出一半的文件也可能被重复处理。

subprocess.run() 能提供区分这些情况所需的信息。下面的例子用当前 Python 解释器模拟正常退出、报错退出和运行超时,再用临时目录里一个不存在的路径模拟启动失败。复制后可以直接运行,无需安装其他工具。

import subprocess
import sys
from pathlib import Path
from tempfile import TemporaryDirectory


def as_text(value):
    if isinstance(value, bytes):
        return value.decode("utf-8", errors="replace").strip()
    return (value or "").strip()


def run_job(label, command):
    try:
        result = subprocess.run(
            command,
            check=True,
            capture_output=True,
            encoding="utf-8",
            errors="replace",
            timeout=2,
        )
    except subprocess.TimeoutExpired as error:
        print(label, "超时", error.timeout, as_text(error.stdout))
    except subprocess.CalledProcessError as error:
        print(label, "退出失败", error.returncode, as_text(error.stderr))
    except FileNotFoundError:
        print(label, "启动失败,找不到可执行文件")
    else:
        print(label, "成功", as_text(result.stdout))


python = [sys.executable, "-u", "-c"]
run_job("正常", python + ["print('ready')"])
run_job("非零退出", python + [
    "import sys; print('invalid config', file=sys.stderr); sys.exit(2)"
])
run_job("慢任务", python + [
    "import time; print('started'); time.sleep(8)"
])
with TemporaryDirectory() as folder:
    run_job("缺少程序", [str(Path(folder) / "missing-program.exe")])
正常 成功 ready
非零退出 退出失败 2 invalid config
慢任务 超时 2 started
缺少程序 启动失败,找不到可执行文件

退出失败说明子进程已经启动并返回了非零退出码。check=True 会把这个结果变成 CalledProcessError,从中可以取到退出码和捕获的标准错误。例子中的 invalid config 直接指向配置问题。如果改用 check=False,就要自己检查 result.returncode。

超时说明子进程在限定时间内没有结束。run() 会终止并等待它直接启动的子进程,再抛出 TimeoutExpired。该异常中的部分输出可能是字节串,即使正常返回时使用了文本模式,所以例子用了 as_text() 统一处理。-u 让示例子进程及时刷出 started,避免缓冲造成误判。实际工具如果还会派生子进程,清理进程树需要单独处理。

启动失败发生在程序运行之前,常见原因是可执行文件不存在,也可能遇到权限错误。用参数列表传入程序和参数,路径有空格时也无需手动拼接引号。把错误类型、退出码或超时上限写入日志,输出量较大时写到日志文件。决定是否重试前,先核对命令已经产生的文件或外部操作,尤其是会覆盖文件或提交请求的任务。

参考资料为 Python 标准库《subprocess — Subprocess management》中的 run() 和异常章节。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。