1. 查找与压缩,为什么是 Linux 操作里的两条腿
接手一台 Linux 服务器,我一般先干两件事:查清楚东西都在哪儿,再想办法把占地方的挪走或变小。这两件事听起来基础,但绝大多数线上事故,比如磁盘被日志写满、找不到某个配置文件、备份包传不过去,最后都会落到"查找"和"压缩"这两个技能上。
很多人学 linux 常用命令时,会把 find、grep、tar、gzip 分开记,每个命令背一堆参数,结果到现场不知道用哪个。实际上,查找和压缩是一套组合拳:先用查找定位文件,再用压缩减少体积。比如排查磁盘空间不足时,先用du和find找出大文件,接着把老日志打包压缩,然后再决定是删还是归档。这一套流程走下来,磁盘压力立刻缓解。这篇文章不打算按手册给你抄一遍命令大全,而是把我实际用下来觉得最靠谱的查找和压缩思路整理出来,附带踩过坑的细节。
适合谁看?刚接触 Linux 的运维和开发、准备 linux 面试题的求职者,以及那些已经会用find和tar简单命令,但遇到复杂场景和诡异报错时不知道怎么处理的人。看完之后,你至少能独立完成一次"找文件—看内容—打包压缩—安全解压"的完整操作,并且知道自己为什么选这条命令而不是另一条。
1.1 一次真实故障排查的启发
有次一台业务服务器的/分区使用率到了 97%,应用开始报“No space left on device”。我第一反应不是上去乱删,而是先执行这条命令:
find / -xdev -type f -size +1G -exec ls -lh {} \;-xdev很重要,它让 find 不要跨文件系统,否则会把/proc、/sys这些虚拟目录也扫进去,轻则慢,重则把系统卡死。-size +1G找出超过 1G 的普通文件,-exec ls -lh {}把找到的文件列出大小。结果发现罪魁祸首是/var/log/nginx下一个没被 logrotate 处理的 access.log,已经 4.7G 了。
当时我直接把这个日志打包压缩再清空,用的是tar和gzip的组合。整个排查过程不超过五分钟,靠的全是查找和压缩的基本功。所以别觉得这两个命令太简单,关键时刻它们就是救命的。
1.2 两者背后的共同思维:做数据治理
把查找和压缩放在一起理解,其实是一种数据治理思维。查找解决的问题是"我要的东西在哪里、长什么样、占多少空间",压缩解决的问题是"这个东西能不能变小一点、能不能打包带走"。前者帮你定位数据,后者帮你减小数据的存储和传输成本。
实际工作中,这两个动作经常交替使用:先find找到一批日志,再用tar打包压缩;先grep看日志内容确认没报错,再决定是否把这批文件归档。理解了这个循环,你的 linux 操作水平会明显上一个大台阶。
2. 查找命令家族怎么选:which、whereis、locate、find、grep
很多新手一提到查找就只想到find,实际上 Linux 下的查找命令有好几个,各自解决的问题不同。选错工具,要么结果为空,要么慢到怀疑人生。
2.1 五种查找命令的分工
| 命令 | 查找对象 | 数据来源 | 实时性 | 典型场景 |
|---|---|---|---|---|
which | 可执行文件 | PATH 环境变量 | 实时 | 确认某个命令装在哪个目录 |
whereis | 命令、源码、man 手册 | 系统预设目录 | 实时 | 找命令的配套文件 |
locate | 文件名 | updatedb 构建的数据库 | 依赖库更新 | 快速按文件名定位 |
find | 文件名、类型、大小、时间、权限等 | 实时遍历目录树 | 实时 | 复杂条件搜索、定时清理 |
grep | 文件内容 | 逐个读取文件内容 | 实时 | 在日志/代码中找关键词 |
这五个命令不是竞争关系,而是互补关系。我自己的选择逻辑很简单:找命令用which或type,找文件路径用locate或find,找内容用grep。如果追求速度且不要求最新的文件,locate是首选;如果条件复杂或者文件是刚新建的,必须用find。
2.2 命令查找的隐藏坑:alias 和 PATH
这里必须说一个坑:which ls可能不会显示/usr/bin/ls,而是显示ls: aliased to ls --color=auto。因为在 bash 里,ls可能是一个别名。遇到这种情况,用type -a ls能看到完整信息:
$ type -a ls ls is aliased to `ls --color=auto' ls is /usr/bin/ls还有一个经典案例:明明软件装了,却提示 command not found。这多半是 PATH 没包含安装目录,比如手动编译安装的软件放在/usr/local/nginx/sbin,执行which nginx找不到,直接运行也报错。解决办法是改 PATH 或用绝对路径,但排查思路要清晰:先echo $PATH看当前路径,再用find / -name nginx -type f 2>/dev/null去全盘找一下。注意2>/dev/null把权限报错丢掉,否则输出会被 Permission denied 刷屏。
2.3 locate 的利与弊
locate的搜索速度比find快一个量级,因为它查的是预先生成的数据库。但代价是数据库不是实时更新的,新创建的文件可能查不到。用之前先sudo updatedb更新一下数据库。在大量文件且规律明显的场景下,locate的体验远好于find,比如我要找所有叫nginx.conf的文件:
sudo updatedb locate nginx.conf如果你发现locate命令不存在,说明系统没装 mlocate 或 plocate 包,Debian/Ubuntu 系执行sudo apt install plocate,CentOS/RHEL 系执行sudo yum install mlocate就能装上。
3. find 的完整姿势:用五维定位法搞定绝大多数搜索
find是 Linux 查找功能的核心,参数繁杂,但拆开看就是五个维度:名字、类型、时间、大小、权限。掌握了这五个维度的组合,你基本可以应对生产中 90% 的查找需求。
3.1 按名字和类型定位文件
最常用的就是-name和-type。-name支持通配符,但要注意通配符要加引号,防止被 shell 提前展开:
find /opt/app -name "*.log" find /etc -type f -name "*.conf" find /var -type d -name "cache"-type的常见取值包括f普通文件、d目录、l符号链接、ssocket 文件。找 socket 文件在排查服务连接问题时非常有用,比如:
find / -type s 2>/dev/null如果想忽略文件名大小写,用-iname。比如找所有以 test 开头的文件,不管是大写 Test 还是小写 test 都能命中:
find /tmp -iname "test*"3.2 按时间、大小、权限过滤
时间维度是运维排查的利器。找最近三天内被修改过的日志文件:
find /var/log -type f -mtime -3这里的-mtime -3表示 3 天内修改过,+30表示 30 天前,3表示刚好第 3 天。类似的还有-atime访问时间和-ctime状态变更时间。如果你的系统里文件非常多,用-mmin -60可以精确到分钟,适合排查"刚刚发生了什么变化"。
大小维度也很常用。找大于 500M 的文件:
find / -type f -size +500M -exec ls -lh {} \; 2>/dev/null权限维度用于安全排查,比如找出所有其他用户可写的文件:
find /home -type f -perm -002这里-002表示"其他用户可写",-perm -表示这些权限位都必须设置。这个命令在做安全基线检查时经常用到。
3.3 控制遍历范围:-maxdepth 与 -prune
find 默认会递归遍历整个目录树,目录层级很深时效率极低。加-maxdepth限制深度是最直接的优化方式:
find / -maxdepth 3 -type f -name "*.conf"另一个高级技巧是-prune,它能把命中的目录直接从搜索范围里剪掉。比如我想在/var下找日志文件,但要跳过/var/lib/docker,避免扫到容器层那成千上万个文件:
find /var -path "/var/lib/docker" -prune -o -type f -name "*.log" -print这条命令的优先级顺序是:先判断路径是不是/var/lib/docker,如果是就剪掉;如果不是,再判断是不是名为.log的普通文件。-o表示 or 逻辑,-print负责输出。理解-prune之后,find 在大目录的搜索速度能提升一个档次。
3.4 find 为什么不是二分查找
有同学问我:find 能不能像二分查找那样,时间复杂度是 log n?这个理解有偏差。二分查找的前提是数据有序且可以随机访问,但文件系统目录结构是一棵多叉树,find 搜索时的真实路径是从根目录开始递归遍历,复杂度通常接近 O(n)。你没法对目录树做二分,因为目录的条目并不是按文件内容排序的。
所以想提升搜索效率,靠的不是算法层面的二分,而是减少遍历范围:用-maxdepth控制深度,用-prune剪掉无关目录,或者提前用locate这种建索引的方式。这个概念偏差在 linux 面试题里偶尔会出现,能把"为什么 find 不是二分查找"讲清楚,说明你对文件系统结构是有理解的。
4. 内容查找与管道组合:grep + find 的高效协作
find按文件名和属性找,但很多时候你需要根据文件内容来判断,这就需要grep出场。两者一组合,很多事情就变得简单了。
4.1 grep 的常用参数
grep的基础用法是grep 关键词 文件,但实际工作中我会常用这几个参数:
-r递归搜索目录-n显示行号-i忽略大小写-v反向匹配--include指定搜索的文件类型-l只显示包含匹配内容的文件名
比如想在整个项目里找出所有调用某个接口的代码,忽略大小写并显示行号:
grep -rin "getUserInfo" /opt/project/src想在日志目录里只搜.log文件中的 ERROR,避免把.txt也扫进去:
grep -rn --include="*.log" "ERROR" /var/log/nginx4.2 find + grep 的经典组合
虽然 grep 支持递归,但在目录特别大的时候,先让 find 做一轮筛选再交给 grep,效率会更高,而且可以叠加更多条件。比如找出/data下最近两天改过的 Java 文件里含有 “TODO” 的:
find /data -type f -name "*.java" -mtime -2 | xargs grep -n "TODO"这里用管道把 find 的结果传给 xargs,再交给 grep 处理。xargs 的作用是把前一个命令的输出转成后一个命令的参数。简单场景下直接grep -r就行,但组合方式可扩展性更强。
4.3 xargs 处理空格和特殊字符的坑
xargs 有一个著名陷阱:文件名里如果有空格,默认会被切分成多个参数。比如find . -name "*.txt" | xargs rm,遇到my file.txt就会出问题。解决办法是使用-print0和xargs -0,用\0作为分隔符:
find . -type f -name "*.log" -print0 | xargs -0 rm -f这个写法在文件名带空格、中文、特殊符号时是安全的。我再强调一遍:凡是find要传递给后续命令处理的,优先用-print0 | xargs -0这种组合,别省这几下键盘敲击。
5. 压缩到底在压缩什么:tar、gzip、bzip2、xz、zstd 的本质区别
聊压缩之前,先纠正一个高频误区:tar本身不压缩,它只做打包,把一堆文件合并成一个文件;真正压缩的是 gzip、bzip2、xz、zstd 这些算法。tar 只是一个容器,可以挂不同压缩算法。
5.1 tar 为什么只是打包工
tar 全称是 Tape Archive,从磁带备份时代流传下来的。它把多个文件连同目录结构、权限、属主信息串成一个流。这也是为什么传输和备份时都用 tar 而不是直接用 gzip 去压某个目录——gzip 只能压单个文件,压不了目录结构。你能看到tar.gz、tar.bz2、tar.xz这类扩展名,本质上都是 tar 打包后再接一个压缩算法。
5.2 主流压缩算法对比
| 算法 | 扩展名 | 压缩率 | 压缩速度 | 解压速度 | 适用场景 |
|---|---|---|---|---|---|
| gzip | .tar.gz | 中等 | 快 | 快 | 最通用,兼容性最好 |
| bzip2 | .tar.bz2 | 较高 | 较慢 | 较慢 | 追求压缩率且不介意速度 |
| xz | .tar.xz | 最高 | 很慢 | 尚可 | 发行版、软件源码包 |
| zstd | .tar.zst | 高 | 极快 | 极快 | 大文件、高频备份 |
| lz4 | .tar.lz4 | 较低 | 极快 | 极快 | 要求速度第一的临时备份 |
从我用过的经验来看,日常备份首选 gzip,没有特殊原因就不要换。xz 压缩率确实高,但压缩一个几个 G 的目录时会慢到让人怀疑人生,适合对体积极度敏感的发布场景。zstd 是后起之秀,兼顾速度和压缩率,很多现代工具都开始默认支持,但老服务器上不一定装,使用前确认一下环境。
5.3 压缩率、时间和 CPU 的取舍
压缩本质是用 CPU 时间换存储空间。同一个文件,gzip 压完可能 200M,xz 压完可能 150M,但 xz 多花了三倍时间。我见过有人为了追求极致压缩率,在一台低配服务器上压十几 G 的备份,结果机器 CPU 跑到 100%,服务直接卡顿。这种场景下,用 zstd 或者干脆按文件类型跳过已压缩的格式,才是更明智的选择。
还有一个经验:日志和文本文件压缩率很高,能压到原来的 5% 到 10%;但 JPEG、PNG、视频这些本身已经压缩过的文件,再压也省不了多少,纯粹是浪费 CPU。遇到这些文件,备份时可以考虑用 tar 打包但不压缩,或者用tar --exclude排除掉它们。
6. 打包、压缩、解压、查看的完整实操流程
理论说完,上真命令。这一节我按实际使用频率,把打包压缩解压的完整流程整理出来。
6.1 最常用的打包压缩命令
把/opt/app目录打包并用 gzip 压缩:
tar -czvf app_backup.tar.gz /opt/app参数拆解:-c创建归档,-z用 gzip 压缩,-v显示过程,-f指定归档文件名。-z可以换成-j(bzip2)或-J(xz),如果你追求 zstd,用--zstd:
tar --zstd -cvf app_backup.tar.zst /opt/app如果想排除某个子目录,加--exclude:
tar -czvf app_backup.tar.gz --exclude="/opt/app/logs" /opt/app注意--exclude的参数最好写绝对路径模式,否则很容易出现"排除了但没排除掉"的诡异情况。
6.2 解压并保持权限与属主
解压常用的是-x替换-c:
tar -xzvf app_backup.tar.gz -C /tmp/restore-C指定解压到哪个目录。这一步我建议永远养成先-C指定目录的习惯,因为 tar 包里的文件路径如果带有根路径,解压时可能会释放到意外位置。保持权限属主是 tar 的默认行为,前提是执行解压的用户有相应权限。跨机器恢复备份时,如果提示权限不足,先看看是不是用普通用户解压了需要 root 属主的文件。
用 root 解压后,/tmp/restore下文件属主不会丢失,这一点是 tar 拷贝目录结构比cp -r更可靠的原因之一。
6.3 查看压缩包内容而不解压
不想解压,只想看看 tar 包里有什么,用-t:
tar -tzvf app_backup.tar.gz | head -n 20-t列出归档内容,-z告诉 tar 先解压再列出。这个命令在确认备份是否完整、想找包里某个单文件时很有用,比直接解压整个包快得多。查完可以直接提取单个文件:
tar -xzvf app_backup.tar.gz opt/app/conf/nginx.conf -C /tmp/提取时路径要和包内路径完全一致,所以先用-t看清楚路径结构。
6.4 跨机器传输与 qcow2 镜像压缩
打包压缩之后往往要传输。大文件建议走 ssh 管道,避免在本地生成中间文件:
tar -czvf - /opt/app | ssh user@10.0.0.8 "cat > /backup/app_$(date +%F).tar.gz"这里-f -表示输出到标准输出,再通过管道送进 ssh。日常备份脚本里,这个写法很常见,省去本地磁盘空间。
如果遇到的是虚拟机的 qcow2 镜像文件,不要直接用 tar 去压,因为镜像里包含大量空白空间,压缩效率极低。正确姿势是用qemu-img做压缩转换:
qemu-img convert -c -O qcow2 vm_origin.qcow2 vm_compressed.qcow2-c就是压缩标志。转换完成后检查一下新镜像,确认无误再替换旧文件。这种场景在私有云和虚拟化环境的运维中经常遇到,属于"查找和压缩"技能的跨领域延伸。
7. 这些年踩过的查找与压缩的坑
命令都会用之后,真正拉高水平的反而是各种边角坑。我把自己踩过的、以及带新人时见过的高频问题集中说一遍。
7.1 解压到当前目录导致文件散落
有一次同事解压一个包,没加-C,直接把一堆.conf文件释放到当前目录,覆盖了同名文件。tar 包内如果路径是相对路径,解压时就会直接落到当前目录。所以解压前必做两件事:第一,tar -tzvf看路径结构;第二,提前建好目标目录并用-C指定。
7.2 中文文件名与 Windows 解压乱码
Linux 下用tar打包的文件名默认是 UTF-8 编码,Windows 自带解压工具对 UTF-8 的 tar 包兼容性时好时坏,尤其是老版本系统,解压出来中文文件名全是乱码。之前传一份资料给同事,对方反馈全是"锟斤拷",其实就是编码问题。解决方案有两个:一是在 Windows 上用 7-Zip 解压,它对 UTF-8 支持更好;二是在 Linux 打包时避免中文文件名,用拼音或英文代替。涉及跨平台传递文件时,这一点提前处理好能省一大堆沟通成本。
7.3 find -delete 的先验证习惯
find支持-delete直接删文件,配合时间条件可以快速清理过期文件:
find /var/log/nginx -type f -name "*.log" -mtime +30 -delete但这个命令极其危险,一旦条件写错就可能误删在线日志。我自己的规矩是:先执行不带-delete的 find,把结果列表看一眼,确认没错再执行删除。要检查更稳妥,用-print代替-delete看输出。如果文件量很大,可以先mv到临时目录而不是删,确认无误后统一清空,给自己留一条后悔药。
7.4 符号链接和权限对打包的影响
tar默认会保留符号链接本身而不是跟随目标,所以打包/usr/bin/foo的软链接时,同僚解压后可能只是一个失效的链接。如果需要跟随链接指向真实内容,要用-h参数。这一区别在备份应用目录时经常引发"为什么解压后程序跑不起来"的疑问。
权限方面,解压 tar 包后如果二进制程序执行报Permission denied,不要急着chmod 777,先看是不是解压时属主不匹配。tar 会把属主信息一并解压,但普通用户无法恢复 root 属主,在你当前用户下看到的权限可能和预期不同。用ls -l确认属主,再用chown调整,这才是有理有据的做法。
查找和压缩这两个能力,看起来是 linux 常用命令里最简单的一档,但真正用好的前提是你理解它们的边界:find 是实时递归遍历,locate 是索引查库,grep 是内容扫描,tar 是打包容器,压缩算法各有取舍。把它们拆开理解,再组合使用,遇到"磁盘满了找不到大文件""日志太多不知道先处理哪些""备份包太大传不过去"这类问题,你自然就知道第一步该敲什么命令了。