Linux tar命令完全指南:从归档压缩到增量备份与性能优化
发布时间:2026/10/14 16:29:44 锦皓数字建站

说实话tar命令是我在日常操作 Linux 时用到最多的命令之一但也是被误解最多的命令之一。很多人觉得它只是“打包压缩”习惯性把.tar.gz和.zip归为一类也有人只记住了-czvf和-xzvf两串参数换一个场景就不知道怎么组合了。这篇文章我想把tar从基础到进阶的用法拆开讲清楚包括归档和压缩的区别、常用参数背后的逻辑、压缩算法怎么选、增量备份怎么做、远程备份怎么传以及我在实际项目里踩过的坑。内容适合刚接触 Linux 的初学者也适合已经用了很久但一直没有系统整理过tar用法的开发或运维朋友。我为什么要写这么一份“完全使用手册”因为在我接触过的业务环境里tar几乎承担了所有轻量级备份和发布包打包工作。无论是某个项目的目录快照、机器间传文件还是定期把日志归档tar都是最可靠的第一选择。它不像某些专用备份工具需要额外安装服务端也不像zip那样在文件权限和时间戳保留上存在短板。只要理解了它的核心逻辑你会发现很多复杂场景都能用简单命令组合解决。这篇文章的内容都是我在实际操作中验证过的不是把帮助文档抄一遍而是按“为什么会这样”的思路来写希望能帮你在下次备份或迁移时少走弯路。1. 先把基础打牢Tar 到底是归档还是压缩1.1 一张图搞懂归档和压缩的区别tar的全称是 Tape Archive最早是为了把数据写入磁带设备设计的。它的核心工作是把多个文件、目录合并成一个“数据流”这个过程叫归档archive并不改变单个文件的内容。也就是说tar的“打包”是它的本能而“压缩”是它调用外部算法来完成的额外动作。一个特别容易混淆的点tar -cf只是打包不加压缩参数时生成的文件后缀通常是.tar体积大概率比原目录还大一点因为归档会写入文件头、目录结构等信息。真正把体积变小的是gzip、bzip2、xz这类压缩算法。你可以把这个过程等价想象成搬家tar是负责把所有散件码进收纳箱的搬运工压缩算法是给收纳箱抽真空的机器。两者配合才得到我们常见的.tar.gz或.tar.xz。理解这个区别非常重要。因为在实际场景里不是所有情况都需要压缩。比如你想把某个目录快速复制到另一台机器网络带宽充足但 CPU 有限这时直接使用不压缩的.tar反而更快。我经常用tar -cf - /data/project | ssh target tar -xf - -C /data/project这种方式做网卡级复制不做压缩速度反而更理想。如果一开始就把“tar”和“压缩”划等号很多优化思路就发挥不出来。1.2 必会的第一组参数-czvf 和 -xzvf 逐个拆解新手接触的第一个tar命令往往是tar -czvf backup.tar.gz /data/app看起来像是指令魔咒实际上每个字母都有明确含义。-ccreate创建归档文件。-z通过 gzip 压缩。-vverbose显示正在处理的文件列表。-f指定归档文件的文件名后面必须紧跟文件名。顺序上有个大家容易忽视的细节-f最好放在参数最后因为tar会把-f后面的内容当作文件名解析。写成tar -czf backup.tar.gz /data/app没问题但如果写tar -cfz backup.tar.gz /data/app部分版本的tar可能把z当成文件名的一部分导致命令失败。虽然现代 GNU tar 容忍部分顺序变化但养成-czvf这种排列习惯是最稳妥的。解压命令是tar -xzvf backup.tar.gz其中-x表示 extract提取文件。如果你想先看看包里有什么不急着解开可以用tar -tzvf backup.tar.gz-t是 list 的意思它只会列出归档内容不会写到磁盘。这三个参数组覆盖了日常八成需求打包、解包、查看。这里还要多说一个参数-C它用来指定操作目录。例如tar -xzvf backup.tar.gz -C /data/restore意思就是解压到/data/restore。我建议所有解压操作都尽量带上-C不要“当前在哪个目录就解压到哪个目录”因为你永远不知道归档内部是否带着多层目录结构不带-C很可能把文件散落到当前工作目录里。实际工作中我见过有人直接在根目录解压备份包结果家具全塞进了/下后面清理花了大半天。2. 进阶操作打包和备份组合拳2.1 压缩算法选型gzip、bzip2、xz 怎么选一个老问题-z用 gzip-j用 bzip2-J用 xz压缩速度和压缩率怎么权衡我很难直接给一个“某算法最好”的结论因为选择取决于你的数据特征和机器资源。下面这个表格是我日常选型的参考参数算法后缀示例压缩速度压缩率CPU 占用适用场景-zgzip.tar.gz快中等中日常备份、发布包、网络传输-jbzip2.tar.bz2较慢较高较高归档压缩率要求更高的历史数据-Jxz.tar.xz很慢最高很高最终归档、不常解压的冷数据--zstdzstd.tar.zst很快高低支持 zstd 时的高效替代方案我之前备份过一个大约 8GB 的项目目录里面主要是日志和静态资源。用 gzip 压缩后体积约 2.1GB耗时 3 分多钟用 xz 压缩后体积约 1.2GB但耗时超过 20 分钟。如果这只是日常循环备份我肯定选 gzip因为每天少花 17 分钟换取几百 MB 的磁盘空间不太划算。反过来如果是把一年前的数据打包封存长期不会再读那我就会用-J省出来的空间非常可观。补充一点现代 GNU tar 还支持通过--use-compress-programzstd调用 Zstandard 算法。zstd 的压缩速度和压缩率都处于 gzip 与 xz 之间而且支持多线程。在 Fedora、Ubuntu 等发行版中只要装了zstd就能用。命令类似tar --use-compress-programzstd -cf backup.tar.zst /data/app不过要注意接收方也得安装 zstd 才能解压否则会报Cannot exec: zstd。如果你在公司内部有统一基线环境这点不是问题如果是给外部协作方传包还是老老实实用 gzip 最保险。2.2 排除文件与自定义过滤规则备份项目目录时最烦的就是把node_modules、.git、__pycache__这类缓存目录一起打进去。tar提供了--exclude参数可以指定要排除的路径或通配符模式。举个例子备份一个前端工程tar -czvf frontend.tar.gz /data/frontend \ --exclude/data/frontend/node_modules \ --exclude/data/frontend/.git \ --exclude*.log这里有两个细节。第一--exclude的路径最好与源路径保持一致写成绝对路径或从/开始的完整路径否则可能出现“明明排除了却还是打进去了”的情况。第二通配符模式是匹配成员名的一整段不是正则所以*.log会排除所有以.log结尾的文件这个很直观。当排除规则很多时命令会变得很长也容易写错。tar支持--exclude-from参数从一个文本文件里读取排除规则。假设有一个.tarignore文件node_modules .git *.log /tmp/*备份命令就可以写成tar -czvf project.tar.gz --exclude-from.tarignore /data/project这种方式的另一个好处是规则文件本身可以提交到代码仓库团队里每个人打包时用的过滤规则完全一致不会出现你排除node_modules而同事没有排除的情况。我在实际项目里就是把这个文件放在仓库根目录发布流程直接从里面读取排除规则效果很稳定。还有几个进阶排除参数比如--exclude-tag和--exclude-tag-under。它们的用途是当某个目录下存在指定标记文件如.nobackup时这个目录整体被跳过。这种方法适合备份大目录树时在特定子目录里放一个“不要备份我”的标记文件规则比一堆 path 更灵活。虽然我用得不算频繁但在一个多层子项目结构里这个能力能省掉不少维护工作。2.3 增量备份与差异备份思路tar本身并不像专业备份软件那样做块级增量但它提供的增量模式对目录级别的中小型系统来说完全够用。关键参数是--listed-incremental也可以简写为-g。它需要一个“快照文件”用来记录哪些文件已经备份过以及它们的状态。第一次备份创建全量归档tar -czvf backup-full.tar.gz -g snapshot.snar /data/appsnapshot.snar文件记录了/data/app目录当时的文件元数据和层级信息。第二次备份时还是指定同一个快照文件tar就会对比当前状态只把新增或修改过的文件写进新归档tar -czvf backup-inc1.tar.gz -g snapshot.snar /data/app从命令上看只多了-g snapshot.snar但执行结果会从“把所有文件重新打一遍”变成“只打包增量部分”。如果数据文件数量很多但每天变化量很小这种方式能节省大量时间和磁盘空间。恢复增量备份时需要按顺序操作先恢复全量包再依次恢复每个增量包并且每次恢复都要使用同一个快照文件。示例tar -xzvf backup-full.tar.gz -g snapshot.snar tar -xzvf backup-inc1.tar.gz -g snapshot.snar tar -xzvf backup-inc2.tar.gz -g snapshot.snar这个方案最需要警惕的是快照文件.snar不能丢。一旦丢了后续的增量包就无法正确匹配恢复时可能只得到一个“带有覆盖补丁的残缺目录树”。我在某次项目迁移中吃过这个亏后来把所有.snar文件和归档包放在同一目录并且纳入检查清单。如果你不想维护增量快照还有一个轻量方案是用--newer-mtime或--newer参数按修改时间差打包。比如只备份最近三天改过的文件tar -czvf recent.tar.gz --newer-mtime 3 days ago /data/app这其实就是差异备份的简化版指定一个基准时间所有修改时间晚于该时间的文件都会被包含。优点是不需要持续维护快照缺点是恢复时需要保证基础备份还存在。我平时做“快速临时导出”时会用这个方式正式场景还是推荐-g snapshot.snar。3. 实战场景用 Tar 完成一次完整备份与恢复3.1 备份项目目录并校验归档完整性先说一个我觉得最实用的备份流程。目标/data/app是需要备份的主项目目录包含配置、静态资源、部分脚本。备份文件落到/backup。我的命令是cd /data tar -czvf /backup/app-$(date %F).tar.gz app为什么要先cd /data而不是直接备份/data/app因为归档内部记录的路径会影响解压时的目录结构。如果直接执行tar -czvf /backup/app.tar.gz /data/app包内所有成员的路径就会带/data/app/...前缀解压时也要先重建/data/data/app这样一层层目录。我先进入父目录再备份包内路径就变成app/...解压时结构更干净重命名或迁移也会更方便。如果你的备份目的是完整保留原路径上下文那可以直接写绝对路径这个取决于需求。命令执行完成后先看大小和文件数是否符合预期。用tar -tvzf列出归档内容并检查关键目录是否在列tar -tvzf /backup/app-2025-01-15.tar.gz | head -20 tar -tvzf /backup/app-2025-01-15.tar.gz | grep app/config/app.confhead和grep用来快速验证不打全量解压。接着用sha256sum计算归档包的校验值写入一个.sha256文件。校验文件本身如果和归档放在一起对方解压后可以用sha256sum -c验证完整性sha256sum /backup/app-2025-01-15.tar.gz /backup/app-2025-01-15.tar.gz.sha256这个流程看着简单但已经覆盖了备份的主要环节打包压缩、路径整理、内容结构核对、完整性校验。如果是自动化任务最后几步最好在脚本里加上连接任何一个步骤失败都会中断避免“看似备份成功实际包是坏的”。还有一个容易被忽略的点在打包大目录时终端会话断开可能导致进程被杀。建议用nohup或screen启动命令。比如nohup tar -czvf /backup/app.tar.gz app /backup/backup.log 21 执行后观察backup.log是否正常结束再决定是否清理。我在一次凌晨备份中遇到过 SSH 连接中断导致备份半途而废的情况从那以后凡是耗时超过 5 分钟的备份我都默认挂到后台跑。3.2 恢复时要注意的权限和路径陷阱备份只是第一步恢复才是真正考验方案的地方。很多人在恢复时会遇到文件属主不对、路径被覆盖、权限混乱等问题下面几个点是我觉得最值得写下来的。第一保留权限。tar归档时并不会默认把每个文件的权限、属主和组信息完整写入恰恰相反归档中包含了这些元数据但解压时是否恢复它们取决于参数。GNUtar一般在 root 用户下会尝试保留属主和权限普通用户解压时则可能变成当前用户。如果你明确需要按原权限恢复解压命令要加上--same-permissionstar -xzvf app.tar.gz --same-permissions -C /data/restore不加这个参数在部分系统上可能会以当前进程的umask重新计算文件权限导致原本 600 的密钥文件变成 644。这种事情我遇到过一次恢复之后服务启动失败排查半天发现是权限过宽。另一个相关参数是--ownerroot --grouproot它可以把所有文件强制指定为某个属主适合在迁移到新环境时统一归属。第二绝对路径问题。如果归档内容是以/开头的例如tar -cvzf app.tar.gz /data/app那么解压时tar默认会去掉前导/并显示tar: Removing leading / from member names。这个提示不是错误而是一种安全保护避免归档内容直接覆盖到系统根目录。千万不要随手加-P或--absolute-names除非你非常确定需要绝对路径恢复否则一旦恢复目录写错后果会很严重。第三只提取一部分文件。归档体积很大时不需要全量解压可以这样tar -xzvf app.tar.gz app/config/app.conf这里要注意包内成员的路径必须以“归档内路径”为准不能带前导/。你可以先用tar -tvzf确认路径再指定提取。如果想解压时去掉顶层目录名配合--strip-components1还可以只保留第二层及以下结构tar -xzvf app.tar.gz --strip-components1 -C /data/restore比如包内路径是app/config/app.conf--strip-components1会把它变成config/app.conf。这在我把一个目录迁入另一个项目名时非常有用。3.3 管道与远程备份组合技巧tar有一个特别适合远程传输的特性它可以把归档内容写到标准输出-再通过管道传给另一台机器。这样就不需要先在本地生成一个庞大的中间文件直接“流式”备份。用法如下tar -czf - /data/app | ssh userbackup-server cat /backup/app-$(date %F).tar.gz这里-f -表示归档输出到标准输出。ssh远端命令把接收到的数据管道写入文件。效果等同于远程备份而且本地临时目录不会因为备份文件过大而爆满。反向操作从远端恢复到本地ssh userbackup-server cat /backup/app.tar.gz | tar -xzf - -C /data/restore这也是我很喜欢的一种组合不落盘传输既不占用本地空间也不占用远端空间。唯一的风险在于网络传输中断所以如果网络不稳定建议先走ssh传压缩包再执行本地解压。数据不大时流式方式能省不少事。有人会问能不能在此基础上看到进度可以借助pv工具tar -czf - /data/app | pv | ssh userbackup-server cat /backup/app.tar.gzpv会显示字节数和传输速度对于长时间传输能起到心理安抚作用。不过pv不是系统默认安装的在 Debian 系用apt install pv在 RedHat 系用yum install pv就能装。另外如果对方机器支持tar还可以直接在远端解包tar -czf - /data/app | ssh userbackup-server tar -xzf - -C /data/restore这样远程机器上会直接出现解压后的文件省去中间归档文件。但我个人不太推荐在备份场景用它因为中间没有保存归档包一旦恢复不完整连原始压缩包都没有排查会很被动。最好是远程先落盘一个.tar.gz再决定是否解压和保留。4. 排查问题、性能优化与避坑指南4.1 常见报错与处理建议速查表我把自己在实际使用中遇到的典型报错整理成了表格方便你对照排错现象或报错原因处理建议tar: Removing leading / from member names归档路径包含绝对路径tar 默认去掉了/前缀无需处理这是安全保护不要轻易使用-Pgzip: stdin: unexpected end of file压缩包不完整或传输中断 / 磁盘空间不足被截断重新生成备份检查源目录和磁盘空间tar: Exiting with failure status due to previous errors某个文件读取失败或归档内存在错误查看前面具体报错信息常见原因是文件被删除或权限不足Cannot open: No such file or directory-f指定的路径不可写或设备不存在检查目标路径是否已创建检查是否误把参数顺序写错tar: This does not look like a tar archive文件确实不是 tar 格式或压缩算法指定错误先判断是.tar还是.tar.gz用file命令确认tar: Too many links to file文件系统硬链接数量超过 tar 格式限制换用 POSIX 格式加--formatposix关于file命令我特别想强调一下遇到解压报错时第一时间执行file xxx.tar.gz看文件真实格式比反复调整参数有效得多。很多“奇怪错误”其实是因为文件后缀和实际内容不一致例如把.zip文件改名为.tar.gz然后尝试用 tar 解压自然就会报错。也曾有人在下载超大文件时只拿到一段 HTML 错误页却把它当压缩包存了下来这类问题用file一眼就能识破。另外还有磁盘空间问题。备份一个大目录时如果没留意/backup所在分区的剩余空间写到一半就会No space left on device。这种情况最容易产生“断尾文件”压缩包看似存在实际已经损坏。我建议在备份脚本开头用df -h /backup检查空间或者直接用du -sh估算源目录大小做到心里有数。自动化脚本里可以在归档完成后强制执行一次tar -tzf做验证只要这个命令能正常列出文件基本可以认为压缩包没有被截断。4.2 大目录备份的性能优化经验性能优化是我最想分享的部分。第一次用tar打包超过 20GB 的目录时我用的是-czvf压了一小时后还在跑CPU 占用率很高原因是它单线程跑 gzip。后来我改用pigz它是 gzip 的并行版本可以配合 tar 使用tar --use-compress-programpigz -cvf app.tar.gz /data/app注意这里没有-z而是用--use-compress-program指定外部压缩程序。pigz会利用多核 CPU对于大目录的提速非常明显。我在一台 8 核机器上测试过同样的目录用 gzip 需要 18 分钟用 pigz 大约 4 分钟压缩后体积几乎一样。如果你的系统没有安装pigz用apt install pigz或者yum install pigz即可。还有一个决策是“先打包后压缩”还是“边打包边压缩”。其实tar -czf内部就是边打包边压缩的数据流经过 tar 拼装后马上进入 gzip并不会先产生.tar再压成.tar.gz。所以不需要担心中间临时文件问题。但如果你想在压缩环节做更多控制可以先把归档写到管道再手动压缩tar -cf - /data/app | xz -T0 app.tar.xzxz -T0表示使用所有可用线程这样也能发挥多核优势。不过这里要提醒一句过度压缩可能不是最优解。如果目标是传输到另一台机器gzip 级别的压缩率和速度平衡往往最好在 CPU 性能较弱的机器上甚至直接用tar -cf不压缩会更快前面已经提过这一点。当目录里的文件数量达到几十万甚至上百万时tar的性能瓶颈会从 CPU 转移到文件元数据遍历。这种情况下可以尝试用--files-from先把文件列表写入一个文件再分批打包避免命令参数过长find /data/app -type f -mtime -7 filelist.txt tar -czvf app-last7.tar.gz -T filelist.txt-T参数让 tar 从文件列表读取要归档的路径。这个方式还有一个好处你可以精准控制打包内容而不是每次全目录扫描。注意文件列表里的路径要以/data/app为基准格式尽量遵循 tar 的接受范围最好保留相对路径或绝对路径一致避免出现“成员名混乱”。最后大目录备份时文件系统 I/O 往往才是真正的瓶颈。如果备份和数据访问同时进行可以尝试用ionice降低备份进程的 I/O 优先级ionice -c2 -n7 tar -czf backup.tar.gz /data/app这条命令在 Linux 上有效能让备份任务尽量避免和业务抢磁盘。虽然不同文件系统的表现有差异但整体上这个方法对压力较大的生产环境是友好的。4.3 备份验证与自动化脚本备份没有验证等于没备份这个理念我在很多场合强调过。归档完成后的验证命令很简单tar -tzf backup.tar.gz /dev/null-t会读取整个归档文件列表同时也能识别压缩包是否损坏。如果输出重定向到/dev/null后命令退出码是 0说明压缩包可以正常读取。如果要验证更深的文件内容可以解压到临时目录再做对比但成本会高很多大多数场景下-tzf已经足够。下面是我经常使用的一个自动化备份脚本模板#!/bin/bash SRC/data/app DEST/backup DATE$(date %F) LOG/var/log/backup.log mkdir -p $DEST cd /data || exit 1 if tar -czvf $DEST/app-$DATE.tar.gz app $LOG 21 \ tar -tzf $DEST/app-$DATE.tar.gz /dev/null 21; then echo $(date %F %T) OK app-$DATE.tar.gz $LOG else echo $(date %F %T) FAIL app-$DATE.tar.gz $LOG exit 1 fi find $DEST -name app-*.tar.gz -mtime 30 -delete脚本里除了备份和验证最后还加了一条保留策略删除 30 天前的归档包。很多备份方案坏就坏在“只增不删”磁盘最终被塞满后续备份全部失败。如果你有更严格的保留策略比如保留每周一个、每月一个则需要更精细的规则但至少要先做到过期清理。配合定时任务执行在crontab里这样写0 2 * * * /usr/local/bin/backup-app.sh凌晨两点执行避开业务高峰。注意脚本开头要使用绝对路径因为 cron 环境变量很少PATH可能不包含/usr/local/bin所以在脚本里最好显式声明PATH/usr/local/bin:/usr/bin:/bin。如果日志输出还要远程同步可以在脚本末尾把归档文件用ssh传到另一台机器。自动化虽然省心但我还是建议每隔一段时间做一次“恢复演练”。模拟解压到临时目录确认服务和数据都正常后再清理。不要等到系统真的出问题才去翻压缩包那时候发现包是坏的压力会大很多倍。尤其是增量备份方案全量加增量的恢复顺序会不会出问题只有演练过后才知道。最后分享一个我自己的小习惯我会把常用的 tar 备份命令包一层 shell 函数放在~/.bashrc里。平时只需要敲backup myproject脚本就会自动生成带日期的压缩包并验证完整性恢复时也只需要restore myproject backup-file这样的简短指令省得每次手敲一堆参数。很多看似复杂的运维问题其实都可以通过这种方式提前消化掉。希望这篇从基础到进阶的 manual 能帮你在下一次使用tar时少一点犹豫多一点底气。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。