ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Linux下.Z转.gz:znew命令用法与批量转换实战指南

2026/9/29 16:02:41 拓冰建站 浏览量
Linux下.Z转.gz:znew命令用法与批量转换实战指南 如果你在 Linux 服务器上翻到一批.Z后缀的旧文件第一反应多半是用znew把它们批量转成.gz。这个看似冷门的命令其实是 gzip 工具族里专门处理旧式 compress 压缩包的小工具在数据迁移、归档整理这类活儿里非常能打。.Z格式由老牌 Unix 的compress命令生成今天很多现代工具链已经不太认它而.gz是 gzip 的标准后缀几乎到处都能解。znew 干的事情就是把前者重新压制为后者并且能批量操作、测试校验、保留原始文件比“先解压再用 gzip 压回去”的土办法安全省事得多。这篇我按实际使用顺序把这个工具掰开揉碎讲一遍它解决什么问题、原理上跟手动解压重压有什么差别、每个参数什么时候用、完整批量操作怎么落最后把那些man手册里没写的坑也一并列出来。无论你是运维老手还是刚接触自建机房的开发只要手里攥着几个.Z文件不知如何处理读完这篇都能直接上手。1. znew 是什么为什么这个格式转换工具值得单独写一篇1.1 从 compress 到 gzip.Z 文件为什么还在要理解 znew先得知道.Z是怎么来的。上世纪 80 年代的 Unix 系统上compress是标配压缩命令用 LZW 算法把文件压成.Z后缀。那个年代硬盘和网络都很金贵能压一点是一点所以.Z格式在古董服务器、磁带备份和 UNIX 发行包里非常常见。后来情况变了。一方面 LZW 算法牵扯专利问题另一方面 gzip 采用的 DEFLATE 算法压缩率更好、解压速度也不差于是 GNU gzip 迅速取代 compress成为 Linux 世界的事实标准。数据迁移时你经常会从老归档、旧备份磁带、博物馆级服务器里导出文件一看后缀是.Z而你的脚本、FTP 服务、对象存储策略可能只认.gz。关键问题在于.Z和.gz的文件头完全不同直接改后缀没有任何意义。.Z文件以魔术字节1f 9d开头.gz文件以1f 8b开头解压器靠的就是这个头来识别格式后缀改得再像也没用。所以必须做一次真正的格式转换读旧格式解压再用新格式压缩。这就是 znew 存在的全部意义。1.2 用 znew 而不是“解压再压缩”的三个理由很多人遇到.Z文件的第一反应是先compress -d或gunzip -S .Z解压成原始文件再gzip压成.gz。这套逻辑没错但不优雅且容易翻车。第一个痛点在于临时文件。手动解压重压会先生成一个裸文件如果原始文件很大你的磁盘要同时容纳.Z、裸文件、.gz三份数据空间压力很大。znew 默认使用临时文件但它的临时文件是“边读边压缩”的中间产物不会把完整裸文件摊在磁盘上峰值占用远小于手工方案。第二个痛点在于校验。znew 提供-t参数能够在删除原始.Z之前先测试新生成的.gz能否被完整还原。手工操作时你很容易忘记这步等删掉原文件才发现新包是坏的。第三个痛点在于批量处理。手工方法要写循环、要处理后缀、要处理“目标文件已存在”的场景。znew 本身就能接受多个文件参数也内置了同名.gz的处理策略命令写起来干净很多。我个人有个更直接的类比.Z是 VHS 录像带.gz是 DVD。录像带能看但播放机越来越少你不能在盒子上贴个 DVD 标签就指望蓝光机认它必须走一遍转码。znew 就是那个帮你转码的机器而且自带“转完先校验一下”的保险机制。2. 原理拆解.Z 与 .gz 到底差在哪儿2.1 LZW 与 DEFLATE两种压缩算法的代差.Z背后是 LZW 算法。它在编码时维护一个字符串表把重复出现的片段替换成短码本质是字典压缩。LZW 在 80 年代确实先进但有几个固有短板字典构造策略固定对文本压缩率一般可调参数少很难在速度和体积之间做精细权衡算法早期还受专利限制让一大票 Unix 用户绕道走。.gz背后是 DEFLATE由 LZ77 滑窗匹配加哈夫曼编码组合而成。简单说LZ77 先找重复片段哈夫曼再把出现频率高的码字进一步缩短。这种组合拳对文本、日志、代码、标记语言这类数据的效果明显优于 LZW。同一份英文文档用 compress 压出来可能是原体积的 40%用 gzip 压通常能再低几个百分点如果文件里有大量重复标签或空格差距会更直观。我见过一份 120MB 的 XML 日志.Z压到 41MB转成.gz后只有 28MB。虽然不是每个文件都能享受到这么大红利但累计后非常可观。需要注意如果文件本身已经是图片、压缩包或加密数据两种算法的效果都会很差这时候 znew 未必能占便宜需要用后面提到的-K参数保护自己。另外还有兼容性的代差。.gz格式几乎被所有操作系统和编程语言原生支持Java、Python、Go 的压缩库里都有成熟实现。.Z则在很多现代环境里要靠ncompress这类第三方包才能读写与其让每个下游依赖都装额外包不如统一转成.gz。2.2 znew 的内部流程临时文件、测试与原子替换znew 本身不是独立压缩算法而是围绕gzip和compress的一层编排脚本。执行一个最基本的znew file.Z它大致会做这么几步检查文件后缀必须是.Z否则直接拒绝。检查同目录是否已有file.gz。如果有默认不覆盖而是先把旧的file.gz改名为file.gz~。用 gzip 把file.Z内容重新压缩到临时文件临时文件通常放在同目录或临时目录里名字带随机标记。如果指定了-t在删除原文件前先对临时.gz做一次完整解压测试确保数据流能还原。确认没问题后删除原始file.Z把临时文件重命名为file.gz。这个过程最核心的思路是“原子替换”新文件全部就绪前绝不碰原始文件新文件验证成功后才一换一。正因如此它比手工gunzip gzip更适合处理珍贵的旧数据。管道模式-P会打乱“先写临时文件再替换”的顺序它把解压数据直接通过管道喂给 gzip不落临时文件几乎不占额外磁盘空间。代价是一旦转换中途失败原始.Z可能已经没了。所以我的建议是只有磁盘空间实在告急时才动用-P否则老老实实让它写临时文件安全永远是第一位。3. znew 命令参数详解与示例3.1 命令格式与最基本的用法znew 的使用格式非常朴素znew [选项] 文件名.Z [文件名2.Z ...]一个最简单也是最常见的场景单个文件转换。znew old_backup.Z执行后目录里的old_backup.Z消失变成old_backup.gz。没有任何输出类似 Unix 工具的一贯风格静默即成功。同时转多个文件直接并列传参znew a.Z b.Z c.Z配合 shell 通配符处理一个目录里所有.Z文件znew *.Z这里有个容易被新手忽略的点*.Z是 shell 展开的如果目录里一个.Z文件都没有Shell 会原样把*.Z字符串传给 znew然后 znew 会报“文件后缀不对”。所以批量操作前最好先确认一下通配符确实匹配到了内容防止误触。3.2 每个选项单独说清楚下表把常用选项列出来后面逐个展开选项作用使用场景-f强制覆盖已存在的.gz旧.gz不需要保留直接换新-t测试新.gz可解压后再删.Z数据珍贵转换必须可靠-v输出每个文件的转换明细批量操作时观察进度-9用gzip -9做最大压缩体积敏感、CPU 不敏感的归档场景-K若新.gz不比.Z小保留.Z内容本身不可压缩时防止负优化-P管道模式不写中间临时文件磁盘空间严重不足且愿意承担风险-V显示 znew 版本信息排查环境时确认工具来源-f很容易理解。如果你明确知道同名.gz是废弃文件加它省的先手工删除。注意它不会“跳过旧文件”而是直接覆盖所以使用前最好确认你确实不需要旧文件了。-t是我在所有生产环境里默认都会加的参数。znew 会先对临时生成的.gz做一次完整的gzip -t测试确认数据流能还原后才会删除原.Z。如果测试失败它会保留原始文件并报错。-v会输出类似下面的信息$ znew -v demo.Z demo.Z: 10240 bytes - 6872 bytes具体措辞在不同发行版上略有差异但核心信息都一样原体积、新体积、压缩率变化。批量处理时加-v能帮你追踪每一对文件的处理结果也方便事后留日志。-9让 gzip 采用最高压缩等级速度会变慢但体积通常能再压一点。老数据的迁移往往是一次性任务慢几分钟可以接受文件小一截却能长期节省存储成本所以归档场景我会推荐。-K是我特别建议批量任务里保留的选项。它会在压缩完成后比较新.gz和原.Z的大小如果新文件反而更大或一样大就放弃本次转换把原始.Z留着同时清理掉这个“负优化”产物。内容高度随机的数据比如已经压缩过的包、加密文件完美适合这个参数。-P的细节前面已经说过这里再重复一遍慎用。磁盘满但非要干活的情况我会先尝试清理空间、换目录处理而不是一上来就用-P。3.3 选项组合的实战姿势面对一批重要数据我会用这样一个组合znew -v -t -9 -K *.Z含义很清楚逐个显示转换结果删除原文件前先测试新文件用最高压缩等级如果没变小就保留原.Z。这套组合兼顾了安全、体积和可追踪性。如果目标是快速清理一批不重要、可以重新生成的.Z文件我会简化成znew -f -v *.Z这里-f允许覆盖任何已存在的.gz因为我确定旧的.gz都是临时产物。还有一个小技巧如果你只想知道某个文件转成.gz后能小多少但暂时不想删除原.Z可以先复制一份到临时目录再在副本上执行 znewmkdir -p /tmp/zcheck cp -a data.Z /tmp/zcheck/ znew -v -t /tmp/zcheck/data.Z ls -lh data.Z /tmp/zcheck/data.gz这样可以在不影响线上数据的前提下做一次“试算”特别适合批处理前评估收益。4. 实操全过程从零开始完成 .Z 到 .gz 的批量转换4.1 环境准备与依赖检查znew 是 gzip 软件包的一部分绝大多数 Linux 发行版默认已经安装。可以先确认一下which znew gzip --version如果which znew没输出说明环境里只有 gzip 没有额外装 znew。在 Debian/Ubuntu 上可以用sudo apt install gzip在 RHEL/CentOS 上sudo yum install gzipmacOS 系统一般自带了 znew不过它属于 BSD 工具链选项可能略有出入用前先man znew确认。如果只是想拿样例测试而系统里没有compress命令来生成.Z文件可以装一个兼容实现sudo apt install ncompress然后生成测试文件printf hello hello hello world\n test.txt compress -c test.txt test.txt.Z file test.txt.Z我自己测试时file命令输出通常是“compressd data 16 bits”说明这确实是一份标准的.Z文件。准备好之后下面就可以拿它开刀了。4.2 单文件转换操作记录先看一个带校验的完整转换过程$ znew -v -t test.txt.Z test.txt.Z: 63 bytes - 45 bytes $ ls -lh test.txt* -rw-r--r-- 1 user user 45 bytes ... test.txt.gz这里目录下已经没有test.txt.Z取而代之的是test.txt.gz。因为加了-tznew 在删除原文件之前已经验证过新文件能完整还原。再确认一下格式$ file test.txt.gz test.txt.gz: gzip compressed data到这里单文件转换就完成了。整个过程没有多余的交互适合写进脚本。如果系统里保留了.Z文件但你又不想真的删除它可以把原文件复制一份做演练。这个习惯在批量处理旧数据时特别有用先拿一两个样本跑通再上全量。4.3 批量转换与脚本自动化一次性处理整个目录下的.Z文件最简单的命令是znew -v -t -9 -K *.Z但如果目录里还有子目录或者.Z文件散落在多个层级建议用find配合sh -cfind . -type f -name *.Z -exec sh -c znew -v -t -9 -K $1 _ {} \;这个写法比管道-exec znew {} 更灵活的一点是每个文件都单独调用一次 znew避免一个文件出错导致整个命令退出$1加上双引号确保文件名里有空格也不会被拆开。面对动辄几千个文件的归档目录我会把命令包在一个 Shell 脚本里方便加日志和错误处理#!/usr/bin/env bash set -uo pipefail logfileznew_$(date %Y%m%d_%H%M%S).log find . -type f -name *.Z -print0 | while IFS read -r -d f; do if znew -v -t -9 -K $f $logfile 21; then echo OK $f else echo FAIL $f fi done这里用-print0和read -d 是为了正确处理文件名里的空格和特殊字符属于老运维的常规操作。日志里能清清楚楚看到每个文件是否转换成功失败了也不影响其他文件继续处理。关于磁盘空间你可以在批量执行前先估算du -ch *.Z 2/dev/null | tail -1znew 在非管道模式下需要同时容纳原始.Z和临时.gz所以可用空间至少要比所有待转文件的累计大小多出“新.gz的预计体积”。通常按原体积的 60%~80% 估比较安全。如果空间不够优先清理无用文件而不是直接上-P管道模式。5. 常见问题与避坑指南5.1 高频报错与对应解法下面列出我实际踩过、以及在社区里经常看到的问题。现象原因解决办法znew: filename does not end in .Z传入的文件后缀不是.Z检查文件名或者先用rename修正后缀demo.gz already exists目标文件已存在znew 默认保护确认旧文件无用后加-fPermission denied当前用户对目录没有写权限调整目录权限或用有权限的用户执行转换后新.gz打不开转换过程被中断或磁盘满用gzip -t检查原始.Z最好保留备份新.gz比原.Z还大数据几乎不可压缩加-K让 znew 自动保留.Z磁盘空间不足报错临时.gz和原.Z同时存在清理空间确有必要再考虑-P并做好数据保护第一个问题看着简单实际很坑。有些文件的裸后缀虽然是.Z但其实是压缩包的一截复制到另一个目录后忘了带后缀还有些系统会把.z小写当成另一种历史格式。znew 跟大部分 Unix 工具一样认死理后缀不符合就直接拒绝不会自作聪明猜测。这是优点避免误操作。第二个问题牵扯到 znew 的一个默认策略如果目录里已经有一个demo.gz它不会直接覆盖而是先把这个旧文件改名为demo.gz~再生成新的demo.gz。这个机制本来是好意防止你丢掉旧的 gzip 版本。但在批量脚本里这会导致目录中突然多出很多.gz~文件后续扫描可能误判。所以我处理重要数据前都会先执行ls -lh *.Z 2/dev/null ls -lh *.gz 2/dev/null看一眼目标和源再决定要不要带-f。5.2 容易被忽略的细节符号链接、时间戳与备份符号链接是一个容易忽略的点。如果某个.Z文件是符号链接znew 在转换时可能会直接解引用链接修改指向的真实文件而不是在链接指向的路径下生成.gz。处理由工具自动生成的过期软链时这不算大问题但如果是手工维护的链接可能就把原始目标给替换了。我习惯在批量执行前先检查find . -name *.Z -type l -ls如果有链接先决定要不要保留链接结构。没有把握就先用cp -L展开成普通文件再让 znew 处理。时间戳也是个细节。gzip 默认会把压缩文件内嵌的时间戳设为原始文件的 mtime所以转换后的.gz“内部时间”没有问题但.gz文件本身在文件系统里的 mtime 是当前转换时间。如果你的归档策略要求文件系统层面的时间也保持一致需要手动修复touch -r demo.Z demo.gz不过通常执行 znew 时原始.Z已经删了所以更稳妥的做法是在转换前记录时间戳或者压缩前先用cp -p保留一份完整的属性副本。最后说下备份。znew 虽然内置了-t校验但“能解压”不等于“内容和预期一致”。如果你手上这批.Z是唯一的旧备份我强烈建议转换前先做一次完整复制mkdir -p /backup/z_originals cp -a /data/*.Z /backup/z_originals/转换完成后再在/backup/z_originals里留几天等新.gz被下游处理和抽查过确认没有异常再清理。这个方法笨但可靠。说到抽查我有个习惯批量转换后随机挑几个文件做内容比对zcat old.Z old.txt zcat new.gz new.txt diff old.txt new.txt这里old.Z如果已经删了就从备份目录取。两个压缩包解开后内容必须一模一样差一个字节都说明转换过程有问题需要立刻回溯。还有一个小建议很多人会忽略znew 处理后如果原文件是tar.Z那么新文件通常就是tar.gz脚本里对压缩包类型的判断也要跟着更新。例如某些部署脚本原来写tar tvf package.tar.Z转换后必须改成tar tzf package.tar.gz否则会因为格式判断错误而找不到文件。最后再分享一个我踩过的坑。有一回我反向操作把一批.Z文件直接znew -f *.Z一次性搞定。执行到一半才发现有个同名.gz是上个月的正式产物结果旧文件被 znew 自动改名成.gz~后续又有一个巡检脚本把.gz~当成有效备份读了进去折腾了很久才对上账。从那次以后我给自己定了几条铁律重要数据转换前先列目录默认加-t -K -v转换后立刻用find . -name *.gz -mmin -10抽查新增文件旧的.Z在确认新包可用前绝不删除。这套流程看着多了一两步但恰恰是这些不起眼的动作让数据迁移这件事变得真正踏实。