subprocess.check_output() 比 call() 更安全可靠,因其自动检查退出码并捕获 stdout,失败时立即抛出异常;而 call() 仅返回码且不捕获输出,易致逻辑错误、死锁或忽略失败。

因为 subprocess.check_output() 强制要求命令成功(非零退出码直接抛异常),而 subprocess.call() 默认忽略执行结果,容易让程序继续使用失败命令的输出或状态。
check_output() 自动拦截失败命令
它在底层等价于 subprocess.run(..., check=True, capture_output=True)。只要子进程返回非零退出码(比如 ls nonexistent 返回 2),立刻抛出 CalledProcessError,不会把空字符串、截断输出或错误内容当作有效结果返回。
而 subprocess.call() 只返回一个整数 returncode,不捕获任何输出,也不抛异常——你得自己写 if ret != 0: 判断,漏掉就等于默认“失败也 OK”。
- 常见错误现象:用
call()执行git commit失败(如无改动),返回码 1,但后续代码仍尝试推送,导致逻辑错乱 - 真实场景:CI 脚本中解析
jq输出做判断,若jq因 JSON 格式错误返回 4,call()不报错,check_output()直接中断
输出捕获机制天然防误用
check_output() 必须显式选择是否捕获 stderr(通过 stderr=subprocess.STDOUT 或 stderr=subprocess.PIPE),否则 stderr 会直接打印到终端——这反而暴露了问题;而 call() 的 stdout/stderr 参数若设为 PIPE 却不读取,极易触发死锁(尤其输出量大时)。
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
立即学习“Python免费学习笔记(深入)”;
- 参数差异:
check_output(['cmd'], text=True)默认只捕获 stdout;call(['cmd'], stdout=subprocess.PIPE)不读取就会卡住 - 性能影响:死锁比多一次异常开销严重得多——进程挂起、超时、资源泄漏都是真实后果
shell=True 下的安全风险其实一样
两者都不解决命令注入问题。如果传入 shell=True 且拼接用户输入(如 f"grep {user_input} file"),check_output() 和 call() 同样危险。
真正提升安全性的不是函数名,而是使用方式:
- 优先用列表形式传参:
check_output(['grep', user_input, 'file'])—— shell 解析被绕过 - 绝对避免
shell=True+ 字符串拼接 - 敏感命令(如密码操作)应禁用 stderr 输出:
check_output(..., stderr=subprocess.DEVNULL)
最容易被忽略的一点:很多人以为“用了 check_output() 就安全了”,但忘了它不处理 stderr,默认不捕获,也不校验输出内容本身是否可信——比如命令成功返回了恶意构造的路径字符串,后续 open() 它照样可能触发路径遍历。

















