你的 Linux 系统就像一个巨大的图书馆,里面藏有成千上万本书籍(也就是文件)。当你需要找某一本特定的书时,你该怎么办呢?如果没有一个好的查找方法,这简直像大海捞针。 幸运的是,Linux 提供了几件强大的“寻宝工具”,可以帮助我们快速定位到任何需要的文件。

这一部分,我们将学习两个核心的搜索命令:
locate:一个像图书馆目录一样的快速查找工具。find:一个像侦探一样的深度搜索工具。同时,我们还会接触到一些辅助它们工作的命令,比如 xargs、touch 和 stat,它们会让我们的搜索工作变得更加高效。
locate 命令:闪电般的快速查找locate 是一个非常神奇的命令,它查找文件的速度快得惊人。它的工作原理就像是图书馆的索引目录。图书馆管理员会提前把所有书的位置信息整理成一本目录,当你要找书时,只需要翻阅目录,就能立刻知道书在哪一排哪一架。
locate 也是这样,它依赖一个预先建立好的文件数据库。当你使用它搜索时,它并不是真的去硬盘上一个一个地翻找文件,而仅仅是查询这个数据库。
比如,我们想找所有名字里包含 “zip” 的程序文件。通常程序都放在 bin/ 目录下,我们可以这样尝试:
|$ locate bin/zip /usr/bin/zip /usr/bin/zipcloak /usr/bin/zipgrep /usr/bin/zipinfo /usr/bin/zipnote /usr/bin/zipsplit
locate 会立刻列出所有路径名中包含 bin/zip 的文件。
locate 的数据库是怎么来的?你可能会发现,一个刚装好的系统,locate 命令可能无法工作,但第二天它又神奇地恢复了。这是因为它的数据库不是实时更新的。系统后台有一个叫做 updatedb 的程序,它会每天定时运行一次,扫描整个系统,然后更新 locate 的数据库。
locate 的优点是速度快,因为它查的是索引而不是硬盘。但缺点也同样明显:它无法找到那些在上次数据库更新后才创建的新文件。如果你想立即更新数据库,可以手动以管理员身份运行 updatedb 命令。
find 命令:像侦探一样精准搜索如果说 locate 是个图书管理员,那么 find 就是一位经验丰富的侦探。它不会依赖任何现成的索引,而是会亲自下到“犯罪现场”(也就是你指定的目录)进行地毯式搜索。
虽然速度慢一些,但它能根据文件的各种蛛丝馬跡(比如文件名、大小、修改时间、权限等)来找到目标。
find 的命令结构看起来有点奇特,但掌握之后威力无穷。它的基本用法是告诉它从哪里开始找:
|$ find ~
这个命令会列出你主目录下的所有文件和子目录,结果可能会非常多。但 find 的真正强大之处在于它的“测试”功能。
find 的测试选项我们可以给 find 添加各种测试条件,来缩小搜索范围。
比如,我们只想找目录,而不是普通文件,可以使用 -type d 这个测试条件(d 代表 directory):
|$ find ~ -type d | wc -l 1695
如果只想找普通文件,就用 -type f(f 代表 file)。下面是一些常见的文件类型测试:
我们还可以组合多个测试。比如,寻找所有文件名以 .JPG 结尾,并且大小超过 1MB 的普通文件:
|$ find ~ -type f -name "*.JPG" -size +1M
这里 -name 用来匹配文件名(注意要用引号包起来,防止 shell 提前解释 *),-size +1M 表示大小超过 1MB。+ 表示“大于”,- 表示“小于”,没有符号则表示“精确等于”。
find 支持的测试条件非常多,下面是一些常用的:
find 的操作符有时候,单一的条件不足以描述我们的需求。比如,我们想找出那些“不安全”的文件:权限不是 0600 的普通文件,或者权限不是 0700 的目录。这时,就需要用逻辑操作符把多个测试组合起来。
|$ find ~ \( -type f -not -perm 0600 \) -or \( -type d -not -perm 0700 \)
这个命令看起来像天书,但别怕,我们来拆解一下。find 主要有三个逻辑操作符:
所以,上面的命令可以解读为:找到满足(是文件 并且 权限 不是 0600)或者(是目录 并且 权限 不是 0700)的所有目标。
find 的动作找到文件后,我们通常想对它们做点什么。find 允许我们对搜索结果执行“动作”。
最简单的动作是 -print,也就是把找到的文件路径打印出来。这是 find 的默认动作,所以即使不写,它也会执行。
另一个强大的动作是 -delete,它可以直接删除找到的文件。
|$ find ~ -type f -name '*.BAK' -delete
这个命令会删除所有以 .BAK 结尾的备份文件。
请务必谨慎使用 -delete!它是一个非常危险的动作,一旦执行无法撤销。在执行删除前,强烈建议你先用 -print 动作运行一遍同样的命令,确认搜索结果是否准确无误,然后再替换成 -delete。
-exec 和 xargs除了预设的动作,我们还可以执行任意命令。这就是 -exec 的用武之地。它的格式是 -exec command {} \;,其中 {} 是一个占位符,代表当前找到的文件名。
比如,我们可以用 rm 命令来模拟 -delete 的效果:
|$ find ~ -type f -name '*.BAK' -exec rm '{}' \;
这种方式每找到一个文件,就会启动一次 rm 命令,效率不高。如果我们想把所有找到的文件一次性交给 rm 处理,可以把结尾的 \; 换成 +:
|$ find ~ -type f -name '*.BAK' -exec rm '{}' +
这样会把所有结果组合成一个长长的参数列表,然后只调用一次 rm,效率大大提升。
另一个实现类似功能,并且更灵活的工具是 xargs。它可以从标准输入读取数据,并把它们作为参数传递给其他命令。
|$ find ~ -type f -name '*.BAK' -print | xargs rm
这个命令流把 find 的输出通过管道传给了 xargs,xargs 再把这些文件名组织起来交给了 rm。
如果文件名包含空格,比如 "my photo.jpg",xargs 可能会把它误认为是两个文件。为了解决这个问题,find 提供了 -print0 动作,它用一个特殊的空字符来分隔文件名。相应地,xargs 也提供了 --null 选项来识别这种格式。
|$ find . -name "*.jpg" -print0 | xargs --null echo
这样就能确保无论文件名多么奇怪,都能被正确处理。
让我们动手创建一个“演练场”,来体验一下 find 的威力。
首先,我们创建 100 个目录,每个目录里再创建 26 个空文件:
|$ mkdir -p playground/dir-{001..100} $ touch playground/dir-{001..100}/file-{A..Z}
这里我们用到了 touch 命令。它通常用来更新文件的时间戳,但如果文件不存在,它就会创建一个空文件。
现在,我们可以用 find 来查找所有叫 file-A 的文件:
|$ find playground -type f -name 'file-A'
接着,我们来试试按时间查找。首先,创建一个时间戳参考文件:
|$ touch playground/timestamp
然后,我们更新一部分文件的时间:
|$ find playground -type f -name 'file-B' -exec touch '{}' \;
现在,我们可以用 -newer 测试来找出所有比 timestamp 文件更新的文件:
|$ find playground -type f -newer playground/timestamp
结果会列出所有我们刚刚“触摸”过的 file-B 文件。
locate 和 find 是 Linux 系统中查找文件的左膀右臂。locate 像闪电一样快,适合模糊的、大概的搜索。而 find 则像一位严谨的侦探,虽然慢一些,但能根据极其复杂的条件进行精准定位。
花点时间熟悉 find 的各种用法,它将成为你在 Linux 世界里探索的强大助力。