gzip本身不会损坏源文件,它只读取源文件并写入新压缩文件,源文件保持原样;所谓损坏实为误操作或磁盘空间不足导致的覆盖失败、管道中断或截断等问题。

gzip本身不会损坏源文件,它只读取源文件、压缩后写入新文件(或标准输出),源文件保持原样。所谓“损坏源文件”,实际是用户误操作或配套流程出错所致——比如用gzip -f file.txt覆盖原文件时磁盘写满,导致file.txt.gz不完整,而file.txt已被重命名或删除;或在管道中与mysqldump等命令组合时,因目标磁盘空间不足导致整个流程中断,留下截断的压缩流。
确保源文件安全:避免覆盖式压缩
默认情况下,gzip file.txt会删除原文件、生成file.txt.gz。一旦磁盘满,gzip可能删了源文件却没写出完整压缩包,造成“双失”。正确做法是显式保留源文件:
- 用
gzip -c file.txt > file.txt.gz:只读不删,源文件始终完好 - 加
--keep参数(gzip 1.12+):gzip --keep file.txt,明确禁止删除源文件 - 备份前先
cp file.txt file.txt.bak,再压缩副本,多一层保险
提前检查磁盘空间,拦截写入失败
gzip不主动校验剩余空间,需在调用前人工判断。尤其在自动化脚本中,必须加入空间预检:
- 用
df -B1 .获取当前目录所在分区的可用字节数 - 估算压缩后大小:对文本类文件,gzip通常压缩率3–5倍,可按
$(stat -c '%s' file.txt) / 4粗略预估目标体积 - 写入前检查:
[ $(df -B1 . | awk 'NR==2 {print $4}') -gt $(stat -c '%s' file.txt | awk '{print int($1/3)}') ] || { echo "空间不足"; exit 1; }
管道场景下防止中间文件损坏
像mysqldump ... | gzip > backup.sql.gz这类管道操作,若磁盘满,gzip进程会被系统kill,输出文件截断,但mysqldump可能已部分写入——此时backup.sql.gz是损坏的,且无源SQL文件可回退。
- 务必在重定向前加空间检查,例如:
[[ $(df -h /backup | awk 'NR==2 {print $5}' | sed 's/%//') -lt 90 ]] || { echo "备份分区使用率超90%"; exit 1; } - 用
gzip -c配合临时文件+原子重命名:mysqldump ... | gzip -c > backup.tmp && mv backup.tmp backup.sql.gz,避免残留损坏文件 - 恢复时先用
gzip -t backup.sql.gz验证完整性,再解压,不跳过校验步骤
损坏后快速识别与补救
若已出现gzip: stdin: unexpected end of file或解压失败,说明压缩文件不完整。此时源文件若已被删,只能从备份或日志中恢复;若源文件尚存,立即停止写入该磁盘,按以下顺序处理:
- 运行
gzip -t file.gz确认是否损坏(返回0表示正常) - 用
zcat file.gz | wc -c看能否读出字节,结合ls -l file.gz对比原始大小,判断截断程度 - 若源文件还在,重新压缩;若不在,检查
/var/log/syslog或dmesg中是否有No space left on device记录,定位何时写满 - 清理磁盘后,对关键数据启用监控:如用
inotifywait监听/backup目录写入,配合空间阈值告警











