1. 为什么我今天还要专门写一篇 gzip 的使用说明
说实话,作为一个在 Linux 环境下混了十几年的老运维,我早就把gzip当成和ls、cd一样理所当然的存在了。直到最近带团队,发现好几个新来的同事压缩文件还在用tar -czvf一条命令走天下,问他们 gzip 单独怎么用、-d和-k什么区别、怎么查看压缩包内容不解压,居然都答不上来。我这才意识到,越是这种基础命令,越值得拿出来认真讲一遍。
gzip 是 GNU 项目提供的压缩工具,全称是 GNU zip,专门用来压缩单个文件。它在 Linux 系统里的地位,相当于 WinRAR 在 Windows 里的普及度——但比 WinRAR 更轻量、更底层。几乎所有 Linux 发行版都默认自带 gzip,不需要额外安装,这也意味着你只要学会它,在任何一台 Linux 机器上都能立刻上手,没有任何环境门槛。
这篇内容适合谁看?我认为有三类人:第一类是刚接触 Linux 的初学者,需要把 gzip 这个基础命令彻底弄懂;第二类是日常要用 Linux 做开发或运维的工程师,虽然已经会用tar和gzip组合拳,但遇到单独处理.gz文件的需求还是会卡壳;第三类是准备面试的求职者,因为 gzip 几乎是 Linux 面试题里的常客,但它考的不是背参数,而是你对压缩原理和实际场景的理解。
文章里我会从最基础的用法开始,逐步深入到压缩级别选择、与 tar 的组合逻辑、解压调试技巧、以及 gzip 和其他压缩工具的横向对比。所有内容都来自我实际摸过的机器、踩过的坑,没有一句是纸上谈兵。
2. 从零开始:gzip 的基础操作和核心参数解析
2.1 压缩一个文件:最简单的用法
先看最基本的场景。假设我有一个日志文件access.log,大小是 587MB,我想把它压缩存档。直接运行:
gzip access.log执行完后,你会发现access.log不见了,取而代之的是一个access.log.gz文件。这是 gzip 的第一个重要特性:默认会删除原始文件。它跟 Windows 上"压缩后保留原文件"的习惯不一样,很多人第一次用的时候都会被吓一跳,以为自己把文件弄丢了。其实原始文件并没有丢,它只是被压缩进了.gz文件里,你随时可以用解压命令恢复出来。
压缩完之后的体积,取决于文件内容的重复程度。同样是 500 多 MB 的文本日志,如果里面大量重复访问记录,能压缩到 30-50MB;如果是已经压缩过的图片、视频之类的二进制内容,那 gzip 基本束手无策,甚至可能越压越大。这一点后面我会专门展开讲。
2.2 解压:还原被压缩的文件
要把.gz文件还原成原始文件,用-d参数:
gzip -d access.log.gz执行后access.log.gz消失,access.log重新出现。这个过程同样会删除压缩包,所以如果你既想保留.gz又想得到原始文件,得用-k参数:
gzip -k access.log # 压缩并保留原文件 gzip -dk access.log.gz # 解压并保留压缩包-k参数是 gzip 1.6 版本之后才加入的。如果你用的是一台很老的 CentOS 5、6 系统,直接加-k会报错,这时候可以用组合命令模拟保留效果:
cp access.log access.log.bak gzip access.log mv access.log.bak access.log2.3 查看压缩包内容:不解压也能读文件
很多人不知道,gzip 单独提供了查看压缩包内容的命令,叫zcat。它能把.gz文件的内容直接输出到标准输出,不解压也能看:
zcat access.log.gz | head -20这样可以只查看日志文件的前 20 行,而不需要真正解压出几百 MB 的原始文件。这个操作在日常排查问题时极其常用,比如我想看看这个日志文件是什么格式、什么时间段的内容,一行命令就搞定了,根本不需要付出解压几百 MB 文件的代价。
另外一个相关场景:如果压缩包里的是一份文本配置文件,我懒得解压又想直接搜索某个关键字,可以这样:
zcat nginx.conf.gz | grep "worker_processes"在老的系统上还有zless和zgrep这两个配套工具,作用和zcat配合管道类似,但在新版本 Linux 里更推荐直接用zcat | grep的方式,因为它的行为更可预测,不依赖额外脚本配置。
2.4 查看压缩包信息:不实际解压
除了查看内容,有时候我只想知道这个压缩包压缩前的原始大小、压缩比率、修改时间。这时候可以用gzip -l:
$ gzip -l access.log.gz compressed uncompressed ratio uncompressed_name 33246823 587250000 94.3% access.log-l输出四列信息:压缩后大小、压缩前大小、压缩率、原始文件名。这个命令非常方便,比如我拿到一个来路不明的.gz文件,先gzip -l看一眼它到底多大、压缩率是否正常,再决定怎么处理。
2.5 调整压缩级别:-1 到 -9
gzip 支持 6 个压缩级别,从-1到-9,默认是-6。数字越小压缩速度越快,但压缩率越差;数字越大压缩率越好,但耗时越长。
| 参数 | 说明 | 典型使用场景 |
|---|---|---|
-1或--fast | 最快压缩,速度优先 | 对实时性要求高的场合,比如临时传文件前打个包 |
-6(默认) | 速度和压缩率的平衡点 | 日常使用,绝大多数场景无脑选它 |
-9或--best | 最高压缩率,速度最慢 | 归档不常用的历史数据,压缩时间长可接受 |
我自己实际测试过,一个 1.2GB 的数据库导出 SQL 文件,-1大概需要 40 秒压完,压缩后 180MB;-9需要 3 分多钟,压缩后 158MB。两者差距也就 22MB,但时间差了好几倍。对绝大多数场景来说,我强烈建议就用默认的-6就行,没必要为了那百分之几的体积差异牺牲太多时间。
这里有个很多人忽略的细节:gzip 还会读取环境变量GZIP,如果你在环境里设了GZIP=-9,那么所有 gzip 操作都会默认用最高压缩级别。我踩过一次坑:一台备份服务器上被人设了GZIP=-9,导致所有 gzip 备份耗时暴增,排查了很久才发现是环境变量在捣鬼。所以如果你发现 gzip 压缩突然变慢了,先看一眼env | grep GZIP的输出。
3. gzip 和 tar 的组合逻辑:你每天都在用的 tar.gz 是怎么来的
3.1 为什么单文件压缩不够用
gzip 有一个先天限制:它只能压缩单文件,不能打包整个目录。想象一下,你把一个项目目录里的 100 个文件分别用 gzip 压缩,得到的是 100 个孤立的.gz文件,目录结构完全丢失,这根本没法用于分发或备份。
于是 tar 就派上了用场。tar 的职责是打包,它把一堆文件和目录合并成一个单一的.tar文件,但默认不压缩。gzip 的职责是压缩,它只能针对单一文件。两者组合使用,就能实现"先打包,再压缩",得到我们今天最常见的.tar.gz文件。
3.2 标准组合命令拆解
最常用的命令是这一条:
tar -czvf archive.tar.gz /path/to/directory拆开看这四个参数:
c:create,创建新的归档文件z:通过 gzip 压缩v:verbose,显示处理的文件列表f:指定归档文件名
对应的解压命令:
tar -xzvf archive.tar.gzx:extract,解压归档
这里有个关键点要强调:tar -z参数本质上是调用了 gzip 命令来完成压缩工作。所以你在用 tar 的时候,底层其实就在执行 gzip。这就是为什么搞懂 gzip 的独立用法很重要——任何你希望 gzip 完成的压缩行为,都可以通过控制 tar 的z参数或直接先用tar -cf再用gzip来达到。
3.3 想用 -9 压缩 tar 包怎么办
有人会问:既然 tar 默认用的是 gzip 的-6级别,我想提高压缩率怎么办?两种办法。
第一种,先打包再压缩:
tar -cf archive.tar /path/to/directory gzip -9 archive.tar第二种,使用 tar 的环境变量技巧。tar 在调用 gzip 时会遵循GZIP环境变量约束,所以可以这样:
GZIP=-9 tar -czvf archive.tar.gz /path/to/directory两种方法我实测过效果相同,但第一种更直白,也更符合"我明确知道 gzip 在做什么"的思路。我个人偏向用第一种,因为遇到问题时排查起来更简单——每一层操作都清清楚楚。
3.4 不解压查看 tar.gz 里的文件列表
拿到一个.tar.gz包,想先看看里面有什么,不需要解压,可以用:
tar -tzvf archive.tar.gzt参数表示列出内容,v显示详细信息,z解压 gzip 层,f指定文件。这个命令在日常接收别人传来的包时非常实用,先看清里面的文件结构和权限,再决定要不要解压,能避免解出奇怪的目录结构或者恶意压缩包。
注意这里不能直接用gzip -l archive.tar.gz来看里面有哪些文件,因为对 gzip 来说,这个.tar.gz文件只是一个单一的压缩流,它是看不到内部 tar 结构的。只有 tar 命令才有能力解析这一层。
3.5 流式压缩:gzip 和管道的深度配合
gzip 最强大的能力在于它天生支持标准输入输出,可以和管道深度配合。
比如备份数据库时,不落地中间文件直接压缩:
mysqldump -u root -p mydb | gzip -9 > mydb.sql.gz这样导出的备份文件直接就是压缩格式,省去了解压原始 SQL 文件再压缩的中间环节。恢复的时候反过来解压直接导入:
gzip -dc mydb.sql.gz | mysql -u root -p mydb这里的-d表示解压,-c表示输出到标准输出而不是生成文件。-c参数在管道场景里非常常用,值得单独记住。
再比如想统计一个大量日志压缩文件里的总行数:
zcat access.log.2024-01-15.gz | wc -l整个过程不需要解压出任何临时文件,内存和磁盘开销都很小。这就是 gzip 在 Unix 哲学里扮演的角色:一个灵活的小工具,可以随时嵌入到任何数据流处理链路中。
4. 进阶实操:gzip 在真实运维场景里的组合拳
4.1 批量压缩目录下的所有文件
假设/var/log/myapp/目录下有 100 个日志文件,我想把它们全部压缩成单独的.gz文件,每个文件单独打包,不用 tar。可以用 find 配合 gzip:
find /var/log/myapp/ -type f -name "*.log" -exec gzip {} \;这条命令找到所有.log文件,对每个文件执行 gzip。注意结尾的{} \;,这个是 find 的标准写法,{}会被替换为找到的文件名,\;表示命令结束。
如果你胆子大一点,想用并发来加速批量压缩,用xargs -P:
find /var/log/myapp/ -type f -name "*.log" -print0 | xargs -0 -P 4 -I {} gzip {}-P 4表示同时起 4 个 gzip 进程。实测在四核机器上,压缩 200 个文件速度能提升 2.5 倍左右。但要注意,高并发压缩耗 CPU 很凶,如果是正在处理线上业务的机器,建议-P 2就够了,否则压缩进程会抢业务进程的 CPU。
4.2 定时备份日志并保留 N 天
这是运维场景里最典型的应用。日志每天都在涨,磁盘总会被塞满,所以需要定时压缩并且保留最近 N 天。我写过一个简单的 cron 脚本:
#!/bin/bash # 每日凌晨 0 点归档昨天的日志 YESTERDAY=$(date -d "yesterday" +%Y%m%d) LOG_DIR="/var/log/myapp" LOG_FILE="$LOG_DIR/app.log" # 如果昨天的日志还没轮转,先复制一份再压缩 if [ -f "$LOG_FILE" ]; then cp "$LOG_FILE" "$LOG_DIR/app.log.$YESTERDAY" # 清空当前日志文件,让应用继续写 > "$LOG_FILE" fi # 压缩昨天日志 gzip -9 "$LOG_DIR/app.log.$YESTERDAY" # 清理 30 天前的压缩日志 find "$LOG_DIR" -name "app.log.*.gz" -mtime +30 -delete这个脚本里有个细节:先复制再清空,叫法叫做 copytruncate 策略。直接用mv移动日志文件也行,但很多应用持有文件句柄,mv 之后应用会继续往旧文件里写,新日志文件反而收不到内容。先cp再清空,可以保证应用写日志不中断。这个坑我踩过很多次,特别是 java 应用持有文件句柄的方式特别顽固,用 mv 方案大概率出问题。
4.3 结合 cron 定时压缩不活跃文件
现实中还有一种常见场景:日志文件还在被应用写入,但已经很久没有更新了。这种文件留着占用空间,删掉又怕以后排查要用。我习惯用 find 排除最近 7 天仍在更新的文件,把更旧的文件压缩掉:
find /var/log/myapp -type f -name "*.log" -mtime +7 -exec gzip {} \;-mtime +7表示文件最后修改时间距今超过 7 天。执行后,7 天前的日志全变成.gz,最近的日志保持原样,应用不会受到任何影响。需要搜索历史日志时用 zcat 随时可以看,不耽误排查。
4.4 用 gzip 压缩 HDFS 或对象存储的上传文件
如果你的工作涉及把文件上传到 HDFS 或者 S3、OSS,很多系统支持客户端先压缩再上传。压缩后再传,传输时间能节省一半以上。比如把一个 2GB 的文件压缩完再传:
gzip -k -1 big_file.csv ossutil cp big_file.csv.gz oss://bucket/path/这里用-1是因为上传到对象存储之后往往还需要别的计算程序读取,压缩级别太高反而浪费 CPU,传得快就够了。至于为什么要加-k,是因为上传完成后如果对象存储侧能自动解压,那本地原始文件还需要保留;如果存储侧直接保存压缩形式,那本地.gz和原始文件留一个就行。具体看你的业务设计,但-k给了你后悔的余地,用完之后删掉不需要的那份即可。
4.5 服务器之间传输大文件时的压缩直传
两台 Linux 服务器之间传文件,很多人会先scp再在目标机上压缩,这是绕了远路。正确的做法是压缩流直接走网络:
tar -czf - /data/mydir | ssh user@remote "cat > /backup/mydir.tar.gz"这里的-是 tar 的一个特殊约定,表示输出内容发送到标准输出,而不是写出文件。ssh那边用cat >接住数据流写到远程文件。这样本地不产生中间文件,远程也不需要额外解压再打包,全程只传输一次压缩数据。
同理,如果你想在传输过程中手动指定高压缩级别:
tar -cf - /data/mydir | gzip -9 | ssh user@remote "cat > /backup/mydir.tar.gz"4.6 gzip 和监控命令配合
有时候压缩任务很耗资源,我们想监控有没有问题。比如用top实时看压缩进程的 CPU 占用:
top -b -d 2 | grep -E "gzip|tar"top -b是批处理模式,-d 2是每 2 秒刷新一次,然后用 grep 过滤出 gzip 和 tar 进程的行。压缩特别大的文件时,gzip 进程的 CPU 占用率会到 100%,属正常现象。如果内存占用异常高,那就要检查是不是文件本身有问题,比如有大量重复内容导致压缩算法发疯。
5. 解压与调试技巧:识别 gzip 文件头,解决解压报错
5.1 gzip 文件的文件头结构是什么
gzip 文件不是简单的压缩数据流,它有一段固定格式的文件头。这段文件头的前两个字节是十六进制的1F 8B,这是 gzip 文件的魔数(magic number)。你可以用xxd或od直接查看一个.gz文件的开头:
$ xxd test.txt.gz | head -2 00000000: 1f8b 0800 0000 0000 0000 2a4b 4c4a 04 00 ..........*KLJ..第一行开头的1f8b就是魔数。这个魔数的存在对实际工作很有意义:
- 文件传输后想确认对方发来的是不是 gzip 格式,直接看前两个字节是
1f8b就行。 - 如果
file命令显示某个文件是 gzip compressed data,但gzip -d却报错,多半是文件头损坏了,或者文件被拼接/截断过。 - 在写脚本判断文件类型时,
head -c 2 file | xxd的输出就是取值依据。
5.2 常见的 gzip 解压报错原因分析
我总结过 gzip 解压报错的几种典型情况,按出现频率排列:
第一:文件被截断。最常见的报错是:
gzip: test.txt.gz: unexpected end of file这个报错说明压缩文件的尾部没有正确结束。可能原因:传输中断、磁盘写满、ftp 上传时用了文本模式(把二进制数据当文本处理导致字节被改写)。遇到这种问题别急着删文件,先看文件大小是否和源端一致,用ls -l对比两端。
第二:文件头损坏。报错形如:
gzip: test.txt.gz: not in gzip format注意看报错字符串是 "not in gzip format" 而不是 "compressed data"。前者说明前两个字节不是1f 8b,这个文件可能根本不是 gzip 格式,或者是你用echo "something" > file.gz这种错误方式生成的伪 gzip。可以用xxd看一眼文件头确认。
第三:压缩文件被拼接。有些人用cat a.gz b.gz > c.gz试图合并压缩文件,这种做法在 gzip 里是行不通的。gzip 格式虽然支持多成员串联(多个 gzip 成员拼在一起),但解压出来的内容是拼接后的,不是两个独立文件的内容合并。你多半会得到一个文件内容混乱的结果,或者头部识别成功但后续数据解压失败。
第四:文件名编码问题。如果原始文件名包含非 ASCII 字符,老版本 gzip 解压时会报:
gzip: test-中文.txt.gz: Invalid argument解决办法是解压时强制指定输出文件名:
gzip -dc file.gz > output.txt5.3 处理损坏 gzip 文件的实操抢救流程
损坏的 gzip 文件不一定无救。如果你的.gz文件只是尾部被截断了,但前面大部分数据是完整的,可以用zcat配合管道抢救出一部分内容:
zcat corrupt.gz 2>/dev/null | head -1002>/dev/null把错误信息丢掉,只保留能解压出来的数据。如果前面部分的压缩数据还完整,这个方法能抢救出一部分内容。我自己用这个方法救回过一次损坏备份文件里的关键配置段。
如果连文件头都损坏了,可以通过查找1f8b魔数定位数据起点:
grep -oba $'\x1f\x8b' corrupt.bin | head -5找到魔数出现的偏移位置后,用dd从这个位置开始切出新的文件:
dd if=corrupt.bin of=recovered.gz bs=1 skip=1024 gzip -t recovered.gzgzip -t是测试完整性的命令,如果输出没有报错,说明截取的部分是一个完整的 gzip 流。这个技巧很冷门,但真遇到紧急情况时它是救命的。
5.4 gzip -t 的妙用:快速测试压缩文件完整性
除了解压时看报错,gzip 提供了一个专门测试完整性的参数-t:
gzip -t file.gz如果压缩文件没问题,这条命令没有任何输出,退出码是 0。如果文件损坏,它会打印错误信息,退出码非 0。
在脚本中可以用这个参数做备份文件完整性校验:
if gzip -t "$backup_file"; then echo "备份文件完整" else echo "备份文件损坏,需要重新备份" fi我强烈建议所有定时备份脚本里都加这一步。你以为备份完成了就万事大吉,实际上磁盘坏道、传输中断都可能导致备份文件静默损坏,等到要用的时候才发现打不开,那才是真正的灾难现场。
6. gzip 的缺点和局限:什么时候不该用它
6.1 压缩率不占优势:和 bzip2、xz 的对比
gzip 作为老牌压缩工具,最大的短板是压缩率。同样一份文本数据,我用同一台机器做过实测:
| 压缩工具 | 压缩后大小 | 压缩耗时 | 解压耗时 |
|---|---|---|---|
| gzip -6 | 587MB -> 178MB | 32s | 5s |
| bzip2 -9 | 587MB -> 141MB | 168s | 46s |
| xz -6 | 587MB -> 122MB | 214s | 18s |
| zstd -6 | 587MB -> 148MB | 18s | 8s |
可以看到,xz 压缩率最高,几乎比 gzip 多压出 30% 的体积,但耗时要 7 倍左右。zstd 在压缩速度和压缩率两方面都优于 gzip,这是 Facebook 开源的压缩算法,近几年在 Linux 社区普及很快。
那还要不要用 gzip?我的答案是:要。因为 gzip 的普及度和兼容性是其他工具完全无法替代的。.gz格式在所有 Linux、macOS、Windows 压缩软件中都被原生支持,而.xz或.zst在老旧环境里未必有对应工具。如果你要给客户交付一个压缩文件,.tar.gz永远是那个最保险的选择。
6.2 不能压缩目录、不能处理多文件
前面已经说过,gzip 只能压缩单文件。如果你只给一个目录路径,gzip 会直接报错:
$ gzip /tmp/mydir/ gzip: /tmp/mydir/ is a directory -- ignored这个局限决定了 gzip 必须和 tar 搭配使用。这一点看起来是"缺点",实际上是 Unix 工具哲学的体现:每个工具只做好一件事,然后通过管道和组合完成复杂任务。相比之下 Windows 上的压缩软件都是一体化的,目录和压缩一步到位,但灵活度反而不如 Linux 的模块化设计。
6.3 压缩已压缩的文件是无效操作
gzip 对已经高度压缩的文件(如 JPEG、MP4、ZIP)再压缩,基本没有收益,甚至可能增大体积。这些格式内部已经用了自己的压缩算法,再套一层 gzip 只会增加 CPU 开销和文件体积。
我见过最夸张的案例:有人把一整个目录的 JPEG 图片用tar -czvf打包,结果压缩后比原目录还大了 2KB。因为 JPEG 本身的熵已经很高,gzip 找不到多余的模式去压缩,反而多了文件头开销。
6.4 无法增量备份和随机读取
gzip 是流式压缩,解压时必须从头到尾完整处理整个压缩流。这带来两个特点:
- 不支持随机读取。你想看压缩文件中间某一段的内容,必须从头解压到那个位置,没法像 ZIP 那样直接定位到某个文件。
- 增量更新困难。如果原始文件只改了一行,你也没法只更新压缩包里的那一行,只能全部重新压缩。
这点和 ZIP 形成鲜明对比。ZIP 格式里有集中式目录结构,支持随机访问和增量更新。如果你的业务需要频繁读取压缩包内的局部内容,或者经常小幅修改文件,建议用 ZIP 而不是 gzip。Linux 下用zip命令加上-r参数就能实现类似 Windows 的压缩逻辑。
6.5 低级别压缩的 CPU 开销不可忽视
虽然 gzip 的解压速度很快,但压缩时的 CPU 占用并不低。默认-6级别压缩一个 10GB 文件,在普通服务器上会吃掉一整颗核的 CPU 持续几分钟。如果是高峰期业务机器,这种 CPU 占用会影响服务性能。
我的建议是:大型压缩任务放低峰期跑,或者用taskset把压缩进程绑到空闲核上,甚至可以做成 systemd timer 定期触发。不要在用户访问高峰时段对重要业务文件做高压缩率操作。
7. gzip 和相似命令/工具的横向辨析
7.1 gzip、zip、tar 的区别到底在哪
很多新手把这三者搞混,但它们解决的是不同维度的问题。我用一句话总结:
- gzip 管压缩,只针对单文件。
- tar 管打包,处理多文件和目录,不做压缩。
- zip 同时打包和压缩,具备独立目录结构。
实际工作中的对应关系是:.tar.gz= tar 打包 + gzip 压缩;.tar.xz= tar 打包 + xz 压缩;.zip= zip 自包含的打包压缩。
注意.gz和.tar.gz不是一回事。.gz就是一个独立文件的压缩流,.tar.gz是打包后再压缩的产物。用file命令能看出区别:
$ file a.gz a.gz: gzip compressed data, was "a.txt", last modified: Tue Jan 16 10:00:00 2024, from Unix, original size 56345 $ file a.tar.gz a.tar.gz: gzip compressed data, was "a.tar", last modified: Tue Jan 16 10:00:00 2024, from Unix, original size 665344要根据文件内容选择合适的工具。gzip 的精髓是处理数据流,tar 的精髓是保留目录结构,zip 的精髓是跨平台和随机访问。
7.2 gzip vs bzip2 vs xz vs zstd 的选型建议
| 维度 | gzip | bzip2 | xz | zstd |
|---|---|---|---|---|
| 压缩率 | 低 | 中 | 高 | 中高 |
| 压缩速度 | 快 | 慢 | 很慢 | 极快 |
| 解压速度 | 快 | 慢 | 中 | 极快 |
| 系统默认支持 | 几乎全有 | 常见发行版有 | 常见发行版有 | 较新发行版有 |
| 适用场景 | 日常一切 | 很少用 | 归档冷数据 | 实时日志、大文件快速压缩 |
我的选型建议是:
- 临时文件、日志压缩、网络传输中转,用 gzip 或 zstd,gzip 兼容性最好,zstd 速度更快。
- 冷数据归档、长期保存体积敏感,用 xz。
- bzip2 现在处于尴尬位置,压缩率不如 xz,速度不如 zstd,能不选就不选。
7.3 pigz:gzip 的多线程替代品
如果你确实喜欢 gzip 格式,但嫌它单核压缩太慢,可以试试 pigz(Parallel Implementation of GZip)。pigz 是 gzip 的多线程版本,生成的压缩文件格式和 gzip 完全兼容,也就是说你用 pigz 压出来的.gz文件,用 gzip 解压一点问题都没有。
安装好之后基本用法:
pigz -p 8 -9 big_file.sql-p 8表示使用 8 个压缩线程。我实测用 16 核机器压缩 5GB 数据,pigz 比 gzip 快了将近 6 倍,压缩率还略高一丢丢。如果你机器核心数充足,建议把 pigz 作为 gzip 的平替方案。日常脚本里直接用 pigz 替代 gzip,只要参数里有-d、-c、-k这些基础项,几乎无痛切换。
tar 调用 pigz 也很简单:
tar --use-compress-program=pigz -czvf archive.tar.gz /data/mydir7.4 gzip 的历史和生态地位简要回顾
gzip 是 1992 年由 GNU 项目开发的,最初为了替代 Unix 系统上专有的compress工具而设计。compress用的是 LZW 算法,有专利问题,gzip 改用 DEFLATE 算法(LZ77 + Huffman 编码),回避了专利限制,很快成为 Unix 世界的事实标准。
这个历史背景解释了为什么 gzip 的格式后缀在这么多种压缩工具出现后依然能活到今天:它在最关键的年代完成了标准化的占领,所有网络软件、打包系统、文件传输协议都把 gzip 作为默认压缩格式。HTTP 协议里的Content-Encoding: gzip选项,Linux 内核源码包和软件源码普遍采用.tar.gz分发,都是这个历史地位的直接体现。
8. 我的日常实用建议和几个冷门小技巧
8.1 务必配一个 gzip 专属 alias
我在所有日志服务器上都会配一行 alias,减少手滑的概率:
alias gz='gzip -k' alias zcat='zcat'-k是 gzip 1.6+ 才有的参数,保留原始文件。日常交互式操作我几乎都会加-k,因为压缩完看一眼结果再决定删不删,比直接删除后后悔来得稳当。这个习惯帮我避免过至少三次"手滑把源文件压没了,还要重新下载"的悲剧。
8.2 gzip 和 find 的 mtime 配合能省大量磁盘
历史日志压缩是运维日常工作里性价比最高的操作。一个 40GB 的日志目录,把 30 天前的文件压缩后,通常能省出 70% 以上空间。关键是给 cron 里加一条 find 命令定期跑,全程无人值守。
关键技巧是用-mtime和-name两个条件精确圈定目标,不要用-exec gzip {} \;直接处理所有文件,先把范围测试好,用-print看一遍输出的文件名,再决定是否真的要压缩。
8.3 不要在生产环境用 gzip -9 压大文件
你永远不知道一个 100GB 的数据库导出文件用-9要压多久。生产环境求稳,压缩任务宁可多花一点磁盘,也不要长时间占用 CPU 拖垮业务。默认级别或-1才是生产环境的最佳选择。cpu、磁盘、时间这三个约束里,通常磁盘最便宜,cpu 最贵。
8.4 用 gzip 压缩网络传输流时,先测压缩率
如果你打算走 gzip 压缩流传输文件,先在同一台机器上测一下压缩率。方法是把文件复制一份,用gzip -t验证一下压缩后的完整性和压缩比率。如果压缩率不到 10%,说明这个文件本身已经是高熵数据,压缩传输的收益不大,直接裸传反而更快,因为省掉了 CPU 压缩的时间。
8.5 文件名里的时间戳别放最后
压缩日志时,很多人习惯把时间戳放在文件名末尾:app.log.20240116.gz。这会导致一个问题:ls排序时,同一天的不同文件会按字典序排列,20240116 排在 20240115 前面(因为第二位 1 排在 2 前面?实际数字位数不同会有奇怪结果),导致你无法直观看出时间顺序。正确的命名格式应该是时间戳在前:app.20240116.log.gz,这样ls的自然排序结果就是时间正序,配合tail或日志采集工具时省很多事。这个细节是早期给我的血泪教训:有次排查线上问题,日志文件名排序错乱,找了几十分钟才发现看错了文件。从那以后我所有的归档脚本都统一用"时间在前"的命名规范。
8.6 gzip 压缩后不要立即删除源文件
如果你的备份脚本里是"先压缩再删除源文件",请务必在压缩命令后面加一个gzip -t校验步骤,确认压缩包完好后再删。前面说过,gzip -t的退出码可以帮你判断压缩文件是否完整。这个额外的几秒钟,能避免你在一个月后发现备份文件静默损坏却无源可依的窘境。
我在实际工作中见过太多次"备份系统正常执行、但文件实际已损坏"的案例,根源往往就是缺少这个校验。备份这件事,宁可多几秒也要确认结果。
8.7 留意系统的 gzip 版本
不同发行版自带的 gzip 小版本有差异,主要体现在-k参数支持与否,以及多线程性能细节。写脚本给多台机器用之前,先确认所有目标机的 gzip 版本统一,或者脚本里做兼容处理:
gzip -V版本低于 1.6 的不支持-k参数,脚本里如果用了,在这类机器上会直接报错。一个兼容的写法是先判断版本再决定参数:
if gzip -V 2>&1 | grep -q "1\.[6-9]"; then GZIP_K="-k" else GZIP_K="" fi8.8 终极武器:gzip 管道实时查看压缩中的文件
有时候压缩一个超大文件太耗时,你想看它到底压缩到哪一步了。虽然 gzip 本身没有进度条,但可以配合pv(Pipe Viewer)实现:
pv big_file.sql | gzip > big_file.sql.gzpv会显示管道中的数据流量,但这显示的是已读取的数据量,不是已压缩的数据量。如果你更关心压缩后的产出量,反过来:
cat big_file.sql | gzip | pv > big_file.sql.gz这样pv显示的是 gzip 压缩后输出到文件的字节数,也就是已写入的压缩数据量。对超大文件来说,这个技巧能让你知道任务大致进展,不至于盯着白屏怀疑机器死机了。
9. 最后关于 gzip 的一句话心得
我在实际使用中的体会是:gzip 这个命令看起来简单到只有几十个参数,但真正掌握它的标志,不是你能背出所有选项的含义,而是遇到一个具体场景时,能条件反射地判断出该不该用 gzip、用哪个级别、配合什么其他命令。
它和 tar、find、管道、cron 的配合方式,就是 Linux 日常运维底层的那些毛细血管。能不能熟练地把它们接起来,决定了一个 Linux 工程师处理实际问题的顺畅程度。
如果你今天读这篇文章只记住三件事,我希望是:第一,gzip -k保留原文件,减少手滑风险;第二,zcat/gzip -dc是查看和管道处理压缩文件的钥匙;第三,压缩任何重要文件后,先跑一遍gzip -t再决定删不删除源文件。这三个习惯养成之后,你的 gzip 使用水平就超过绝大多数人了。