gzip在灾备脚本中需联合退出码、stderr内容与上下文状态三者判断:退出码1为通用错误,需结合stderr区分磁盘满或权限不足;127表示命令未找到;141对应SIGPIPE;stdin截断报“unexpected end of file”。应预检磁盘空间、重定向stderr、启用pipefail,并用gzip -t验证完整性。

gzip 在自动化灾备脚本中常用于压缩备份文件,但它的异常表现并不统一——比如磁盘满、权限不足、输入流中断、损坏的源文件、信号中断(如 SIGPIPE)、甚至 stdout 被重定向失败等,都可能让 gzip 静默退出或返回非零码却无明确错误信息。要“优雅捕获”,关键是不依赖单一 exit code,而需结合退出码、stderr 内容、上下文状态三者做联合判断。
识别 gzip 常见溢出场景与对应信号/码
gzip 本身不抛出异常,但会通过退出码和 stderr 输出线索:
- 退出码 1:通用错误(如无法读取源文件、写入目标失败),但不区分原因;需配合 stderr 判断是 “No space left on device” 还是 “Permission denied”
- 退出码 2:命令行参数错误(如 -c 和 -k 同时用),属脚本逻辑问题,应在调用前校验
- 退出码 127:系统找不到 gzip 命令(PATH 问题或未安装),不是 gzip 自身异常,而是环境缺失
- SIGPIPE(退出码 141):常见于管道下游提前退出(如 tar | gzip | ssh 中 ssh 断连),此时 gzip 无法写入,但 stderr 可能为空
- stdin 被截断(如 mysqldump 意外终止):gzip 会报 “stdin: unexpected end of file”,退出码为 1
在脚本中做分层捕获与兜底处理
不要只写 gzip -c file.sql > file.sql.gz || echo "fail"。应封装为可诊断的压缩函数:
- 始终重定向 stderr 到变量或临时文件,避免丢失关键提示
- 检查退出码后,再 grep stderr 内容匹配典型溢出关键词(如
disk quota exceeded、Input/output error、Broken pipe) - 对管道操作(如
mysqldump ... | gzip),用set -o pipefail确保任一环节失败整个管道返回非零码 - 压缩前预检:用
df -B1 . | awk 'NR==2 {print $4}'获取剩余字节数,对比预估压缩后大小(可按原文件 30%~70% 估算),留至少 200MB 缓冲
示例:带上下文感知的 gzip 封装函数
以下 shell 片段可用于灾备脚本中:
safe_gzip() {
local src="$1" dst="$2"
local err_log=$(mktemp)
<pre class="brush:php;toolbar:false;"># 预检磁盘空间(假设目标目录为 dst 所在目录)
local free_bytes=$(df -B1 "$(dirname "$dst")" | awk 'NR==2 {print $4}')
local src_size=$(stat -c "%s" "$src" 2>/dev/null || echo 0)
# 保守估计压缩后为原大小 50%,再加 200MB 安全余量
local need=$((src_size / 2 + 200*1024*1024))
if [ "$free_bytes" -lt "$need" ]; then
echo "[ERROR] Insufficient disk space: need $need B, available $free_bytes B" >&2
return 126
fi
if ! gzip -c "$src" > "$dst" 2>"$err_log"; then
local code=$?
local msg=$(cat "$err_log" | head -n1)
case $code in
1)
if echo "$msg" | grep -q -i "broken pipe\|sigpipe\|pipe"; then
echo "[WARN] gzip interrupted by downstream (SIGPIPE)" >&2
return 141
elif echo "$msg" | grep -q -i "no space\|disk quota"; then
echo "[ERROR] Disk full during gzip compression" >&2
return 122 # 自定义码,区别于系统码
else
echo "[ERROR] gzip failed: $msg" >&2
return $code
fi
;;
127) echo "[ERROR] gzip command not found" >&2; return $code ;;
*) echo "[ERROR] gzip unknown failure (code $code): $msg" >&2; return $code ;;
esac
fi
rm -f "$err_log"
return 0
}
配套建议:日志与恢复友好设计
灾备脚本的目标不是“压完就算”,而是“压完可追溯、失败可重试”:
- 每次 gzip 操作记录完整命令、开始/结束时间、源文件 size、目标文件 size、退出码、stderr 摘要到结构化日志(如 JSON 行)
- 若 gzip 失败且源文件未被破坏(如只是磁盘满),保留原文件并标记为 “pending-compress”,供下次重试
- 对关键备份,压缩后立即运行
gzip -t "$dst"验证完整性,失败则清理残缺文件并告警 - 避免在 /tmp 下压缩大文件——/tmp 可能是内存 tmpfs,空间更紧张;优先选备份根目录所在分区
不复杂但容易忽略:gzip 的“优雅”不在它自身,而在你如何把它放进一个有上下文、有预判、有反馈闭环的流程里。











