Python 命令行工具的退出码:区分正常、超限与输入错误
把一个小工具接进自动化流程时,终端里打印“检查完成”还不够。调用方需要知道检查是否成功、业务条件是否满足,以及下一步该继续、提醒用户,还是排查输入。
最近为“字节边界助手”补充只读文件计数工具时,我把这几个结果明确拆开:文件能正常读取,但超过字节限制,属于一类结果;文件不是合法 UTF-8,属于另一类结果。两者都需要调用方处理,却不应该共用一条含糊的报错。
下面使用这份本地 Python 原型说明退出码与结构化输出如何配合。这里讨论的是已实现的命令行工具,智能体集成仍处于计划阶段。
一、先定义调用方需要区分的结果
这个工具只读取一个明确指定的文件。它以原始字节统计文件大小,严格检查 UTF-8 编码,再与用户提供的非负整数上限比较。
| 情况 | 本工具退出码 | 调用方可采取的动作 |
|---|---|---|
| 文件有效,原始字节数不超过上限 | 0 | 继续后续处理 |
| 文件有效,原始字节数超过上限 | 1 | 展示超出字节数,等待修改 |
| 读取、编码或参数错误 | 2 | 先修正输入或运行条件 |
这是本工具自己定义的接口约定。其他程序未必采用相同含义,调用前需要阅读对应说明。尤其不能把“退出码为 1”一概解释为程序崩溃:在这里,它表示工具完成了检查,并发现文件超限。
二、退出码表示分支,JSON 提供依据
退出码适合做粗粒度判断,具体原因仍应来自输出。工具检查成功时返回 JSON,包含原始字节数、是否携带 UTF-8 BOM、限制值、是否超限以及超出的字节数。
例如,文件仅包含“云😀”,不带 BOM。其 UTF-8 原始字节数为 7。上限设为 6 时,结果中的关键字段如下:
{
"ok": true,
"raw_bytes": 7,
"limit": 6,
"within_limit": false,
"over_by": 1
}
这时 ok 为真,表示读取和编码检查成功;within_limit 为假,表示业务限制没有满足。两个字段表达不同层次的状态,调用方应分别理解。
原型入口使用以下判断,把结构化结果映射到退出码:
return 2 if not result['ok'] else (0 if result['within_limit'] else 1)
如果文件中出现非法 UTF-8 字节,工具返回的则是错误对象,例如包含 ok: false、error: INVALID_UTF8 和错误字节偏移。它不会继续把损坏内容当成有效文本计算业务结论。
三、调用方同时检查退出码与结果
原型的命令格式为:
python byte_boundary.py input.txt --limit 6
在 Python 自动化脚本中,可以通过 subprocess.run 收集退出码、标准输出和标准错误。调用形式使用参数列表,下面的文件名与上限作为参数传入:
import json
import subprocess
import sys
run = subprocess.run(
[sys.executable, "byte_boundary.py", "input.txt", "--limit", "6"],
capture_output=True,
text=True,
)
if run.returncode in (0, 1):
report = json.loads(run.stdout)
print("超出字节数:", report["over_by"])
else:
print("检查未完成,退出码:", run.returncode)
print("标准输出:", run.stdout)
print("标准错误:", run.stderr)
这段调用代码展示的是本工具的正常接口分支。生产调用方还应处理工具进程未能启动、运行超时、输出格式不符合约定等情况,不能只凭退出码就假定 JSON 一定完整。
还有一个容易漏掉的边界:本原型使用 argparse 处理命令参数。缺少必填参数或提供非法上限时,参数解析器会以退出码 2 结束,并把用法提示写入标准错误。此时标准输出可能为空,调用方不能无条件执行 json.loads(run.stdout)。
目前的约定是:文件检查结果使用标准输出 JSON;参数解析错误使用标准错误提示。如果后续希望所有错误都具有同一种 JSON 格式,需要显式调整参数解析入口,并同步修改接口说明及测试。
四、用真实子进程验证接口
仅测试计数函数,无法保证命令行入口真的返回了正确的退出码。因此原型测试中额外启动 Python 子进程,覆盖完整命令调用。
| 测试文件与参数 | 预期退出码 | 核查重点 |
|---|---|---|
abc,上限 3 |
0 | 刚好等于上限也算通过 |
abc,上限 2 |
1 | 超限时仍输出可解析 JSON |
| 非法 UTF-8 字节,上限 2 | 2 | 编码错误不能被当成普通超限 |
| 不存在的文件 | 2 | 读取失败返回明确错误类型 |
| 有效文件,上限为负数 | 2 | 参数错误通过标准错误解释 |
上述五种命令行场景已在本地复核。原型还包含 12 项单元测试,覆盖空文件、中文、表情、BOM、混合换行、非法编码、原文件不变等边界。验证范围是本地 Python 工具,不代表已经完成云端部署或智能体端到端验证。
五、把接口约定写进运行说明
维护命令行工具时,运行说明最好同时给出退出码、输出字段与错误输出位置。否则调用方可能把业务未通过当成运行故障,或者把真正的读取错误误认为“文件需要缩短”。
在这个小工具里,我还保留了两个限制:报告不回显文件正文及路径;工具只读用户指定的单个文件,不扫描目录,也不自动修改原文件。这样调用方拿到的是明确的统计依据,是否修改内容由使用者决定。
这次实践让我更关注命令行入口本身的可验证性:计数结果正确是一部分,调用方能稳定识别结果并走到正确分支,同样需要测试。退出码、JSON 和标准错误共同构成了这份工具的接口。
本文依据“字节边界助手 v0.2”本地原型的 byte_boundary.py、test_byte_boundary.py 及命令行验证记录整理。退出码含义为该原型的设计约定。
- 点赞
- 收藏
- 关注作者
评论(0)