在 Linux 中查找文件和命令

LinuxLinuxBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

引言

在本实验中,你将掌握在 Linux 命令行环境中定位文件和命令的关键技术。你将从使用强大的 find 命令开始,学习如何按名称执行基本搜索,并利用通配符进行更灵活的模式匹配。这种实践方法将引导你创建一个示例目录结构,以安全地练习你的搜索技能。

在此基础上,你将探索如何使用 -execxargs 在搜索结果上执行命令。本实验还涵盖了替代性和专用搜索工具,包括快速、数据库驱动的 locate 命令,用于查找命令二进制文件和手册的 whereis,以及像 aliaswhichtype 这样的实用工具,用于分析命令执行路径。到最后,你将能够熟练地为 Linux 中的任何文件或命令搜索任务选择合适的工具。

使用 find 和通配符执行基本文件搜索

在本步骤中,你将学习如何使用 find 命令,这是 Linux 命令行中最强大的用于搜索文件和目录的工具之一。我们将从基本的文件名搜索开始,并介绍通配符以查找文件模式。

首先,让我们创建一个专门的目录和一些示例文件供我们练习。这确保我们有一个受控的环境来观察 find 的工作方式,而不会影响文件系统的其他部分。

  1. 确保你位于正确的起始目录。本实验的所有工作都将在 ~/project 中进行。
cd ~/project
  1. 创建一个名为 find_lab 的新目录并进入该目录。
mkdir find_lab
cd find_lab
  1. 现在,让我们创建一组文件和一个子目录来搜索。我们将使用 touch 命令创建空文件,使用 mkdir 创建目录。
touch file1.txt file2.log report.txt File1.TXT
mkdir subdir
touch subdir/file3.txt subdir/another.log

你可以使用 ls -R 命令来验证结构,该命令会递归地列出当前目录及其子目录中的文件。

ls -R

你应该会看到类似以下的输出:

.:
File1.TXT  file1.txt  file2.log  report.txt  subdir

./subdir:
another.log  file3.txt

现在我们的测试环境已经准备就绪,让我们开始搜索。

find 命令的基本语法是 find [path] [expression][path] 告诉 find 从哪里开始搜索,而 [expression] 定义要查找的内容。

按精确文件名搜索

要按精确文件名查找文件,请使用 -name 表达式。让我们查找 report.txt 文件。我们将使用 . 作为路径,这告诉 find 从当前目录开始搜索。

find . -name "report.txt"

输出将显示找到的文件路径:

./report.txt

使用通配符搜索

通配符允许你根据模式搜索文件。最常见的通配符是星号 (*),它匹配任何字符序列。

将模式放在双引号 (") 中是一个最佳实践,以防止 shell 在 find 命令能够使用它之前解释通配符。

让我们查找所有以 .txt 扩展名结尾的文件。

find . -name "*.txt"

find 将递归地搜索当前目录 (.) 及其所有子目录:

./file1.txt
./report.txt
./subdir/file3.txt

请注意,File1.TXT 未被找到,因为 -name 执行的是区分大小写的搜索。要执行不区分大小写的搜索,请使用 -iname(不区分大小写的名称)表达式。

find . -iname "*.txt"

现在,输出包含了所有以 .txt 结尾的文件,无论大小写:

./file1.txt
./report.txt
./File1.TXT
./subdir/file3.txt

按文件类型搜索

你还可以指示 find 只查找特定类型的文件系统对象,例如文件或目录,使用 -type 表达式。使用 -type f 表示常规文件,使用 -type d 表示目录。

让我们只查找当前位置中的所有目录。

find . -type d

输出列出了当前目录 (.) 和我们创建的 subdir

.
./subdir

你可以组合表达式来创建更具体的搜索。例如,查找所有以 .log 结尾的文件(非目录):

find . -type f -name "*.log"

此命令将查找所有是文件且名称以 .log 结尾的项目。

./file2.log
./subdir/another.log

你现在已经学会了使用 find 进行名称模式和类型过滤的基本知识。在接下来的步骤中,我们将探索此命令更高级的功能。

使用 find -execxargs 对搜索结果执行操作

在本步骤中,你将超越简单的文件列表。你将学习如何直接对 find 命令找到的文件执行命令。这是一种执行批量操作的强大技术,例如更改权限、删除文件或运行自定义脚本。我们将介绍两种主要方法:find-exec 选项和 xargs 命令。

我们将继续在上一实验步骤中的 ~/project/find_lab 目录中工作。首先,请确保你位于正确的目录。

cd ~/project/find_lab

使用 find -exec

-exec 选项允许你为 find 定位到的每个文件运行任意命令。其语法起初可能看起来有些不寻常:

find [path] [expression] -exec [command] {} \;

  • [command]: 你要运行的命令(例如 ls -lrmchmod)。
  • {}: 这是一个特殊的占位符。find 会将 {} 替换为它找到的当前文件的完整路径。
  • \;: 这是 -exec 命令必需的终止符。反斜杠 (\) 是必需的,以防止 shell 将分号解释为特殊字符。

让我们来尝试一下。我们将查找所有扩展名为 .txt 的文件,并对每个文件运行 ls -l 来查看其详细信息。

find . -name "*.txt" -exec ls -l {} \;

输出显示了运行 ls -l 的结果,每个 .txt 文件都执行了一次:

-rw-rw-r-- 1 labex labex 0 Jun 26 09:45 ./file1.txt
-rw-rw-r-- 1 labex labex 0 Jun 26 09:45 ./report.txt
-rw-rw-r-- 1 labex labex 0 Jun 26 09:45 ./subdir/file3.txt

为了安全起见,find 提供了一个 -ok 选项,它的工作方式与 -exec 相同,但在执行命令之前会提示你进行确认。在执行删除文件 (rm) 等破坏性操作时,强烈建议使用此选项。

让我们尝试删除之前创建的 .log 文件,但这次使用 -ok 来确保安全。

find . -name "*.log" -ok rm {} \;

对于找到的每个文件,find 都会询问你的确认。输入 y 并按 Enter 键批准删除。

< rm ... ./file2.log > ? y
< rm ... ./subdir/another.log > ? y

确认后,你可以通过列出目录内容来验证文件是否已被删除。

ls -R
.:
File1.TXT  file1.txt  report.txt  subdir

./subdir:
file3.txt

使用 xargs

-exec 的一种替代方法是将 find 的输出通过管道传递给 xargs 命令。xargs 从标准输入(由 find 提供的文件路径)读取项目,并使用这些项目作为参数执行指定的命令。

xargs 的主要优势在于效率。虽然 -exec ... \; 对每个文件都运行一次命令,但 xargs 会将文件路径分组,并以更少的命令执行次数(一次处理多个参数)来运行命令。

首先,让我们重新创建刚刚删除的日志文件,以便我们有东西可以操作。

touch file2.log subdir/another.log

现在,让我们使用 findxargs 来列出我们 .log 文件的详细信息。

find . -name "*.log" | xargs ls -l

输出与 -exec 示例类似,但命令结构不同:

-rw-r--r-- 1 labex labex 0 <date> <time> ./file2.log
-rw-r--r-- 1 labex labex 0 <date> <time> ./subdir/another.log

find -ok 类似,xargs 也使用 -p 选项提供“提示”模式。它会显示即将运行的命令,并询问你的确认。

让我们使用此选项再次删除 .log 文件。

find . -name "*.log" | xargs -p rm

xargs 会将文件分组到一个 rm 命令中,并询问你的确认。输入 y 并按 Enter 键。

rm ./file2.log ./subdir/another.log ?...y

你现在已经成功地使用了 -execxargs 来处理搜索结果,这是在 Linux 中自动化任务的一项基本技能。

使用 locateupdatedb 进行快速的数据库驱动搜索

在本步骤中,你将学习一种 find 的替代方法,称为 locatefind 在实时搜索文件系统,而 locate 则搜索一个预先构建的文件路径数据库。这使得 locate 的速度显著更快,但有一个重要的权衡:它只能找到数据库上次更新时存在的文件。

我们将继续在 ~/project 目录中工作。首先,让我们确保安装了必要的工具。

  1. locate 命令由 mlocate 包提供,该包可能默认未安装。运行以下命令来更新你的包列表并安装它。你将使用 sudo,因为这是一个系统范围的安装。
sudo apt-get update && sudo apt-get install -y mlocate

你将看到包安装进度,这是正常的。

  1. 现在,让我们进入前几个实验步骤中的测试目录。
cd ~/project/find_lab
  1. 尝试使用 locate 查找 report.txt 文件。
locate report.txt

在许多系统中,locate 数据库会自动更新,因此你可能会立即看到该文件:

/home/labex/project/find_lab/report.txt

如果你看到了文件路径,这意味着数据库已经包含了关于你最近创建文件的信息。当系统在后台自动运行数据库更新时,可能会发生这种情况。

  1. 如果在步骤 3 中没有看到任何输出,则需要手动更新数据库。使用 updatedb 命令重建数据库:
sudo updatedb

此命令不产生任何输出,但它会在后台运行。完成可能需要几分钟时间。

  1. 运行 updatedb(如果需要)后,再次尝试 locate 命令:
locate report.txt

现在它应该能找到并显示文件的路径:

/home/labex/project/find_lab/report.txt

理解本地数据库的局限性

让我们探讨一下在数据库上次更新后创建新文件时会发生什么。

  1. 首先,让我们在 find_lab 目录中创建一个新文件。
touch special_report.pdf
  1. 尝试定位这个新文件:
locate special_report.pdf

如果系统数据库最近更新过,你可能会看到该文件。如果没有,将不会有任何输出,因为数据库尚未了解这个新创建的文件。

  1. 你可以强制更新系统数据库:
sudo updatedb
  1. 现在再次尝试定位该文件:
locate special_report.pdf

现在你应该看到:

/home/labex/project/find_lab/special_report.pdf

理解数据库更新频率

关键在于 locate 依赖于其数据库的新鲜度。在生产系统中:

  • 系统通常会自动更新 locate 数据库(通常通过 cron 作业每天更新)。
  • 当你需要即时结果时,你可以使用 sudo updatedb 手动更新它。
  • locate 速度极快,因为它搜索的是预先构建的索引,而不是扫描文件系统。
  • 对于查找最近创建的文件,find 可能更可靠,因为它进行实时搜索。

你现在已经了解了 locate 如何通过使用预先构建的数据库提供闪电般的快速搜索,并理解了使用 updatedb 保持数据库最新状态的重要性。

使用 whereis 定位命令二进制文件和手册页

在本步骤中,你将学习使用 whereis,这是一个用于定位命令的二进制文件、源代码和手册页文件的专用命令。与用于通用文件搜索的 findlocate 不同,whereis 经过优化,可以快速找到与系统命令相关的重要文件。它通过搜索预定义的标准 Linux 目录列表来工作,因此速度极快。

让我们开始探索 whereis 命令。你可以处于任何目录,因为 whereis 不会根据你当前的位置进行搜索。为了保持一致性,我们将留在 ~/project 目录中。

cd ~/project
  1. 让我们查找 passwd 命令的位置,该命令用于更改用户密码。
whereis passwd

输出显示了命令名称,后跟其二进制可执行文件和相关手册页的路径。

passwd: /usr/bin/passwd /etc/passwd /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz
  • /usr/bin/passwd: 这是可执行程序。
  • /etc/passwd: 这是系统的用户数据库文件,passwd 命令会与之交互。whereis 通常会将其结果中包含的重要配置文件。
  • /usr/share/man/...: 这些是命令的压缩手册页。
  1. 你可以过滤结果,只显示特定类型的文件。要只查看与 passwd 相关的二进制文件,请使用 -b(binary)标志。
whereis -b passwd

这将输出限制为仅包含可执行文件和相关文件,不包括 man 页。

passwd: /usr/bin/passwd /etc/passwd
  1. 类似地,要只查找手册页,请使用 -m(manual)标志。当你想要了解某个命令有哪些可用文档时,这非常有用。
whereis -m passwd

输出现在只列出了 man 页的位置。

passwd: /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz
  1. 理解 whereis 的局限性很重要。它只搜索标准的系统目录。让我们尝试查找我们在 find_lab 目录中创建的 report.txt 文件。
whereis report.txt

该命令仅返回文件名,但没有路径:

report.txt:

发生这种情况是因为 report.txt 位于你的主目录 (~/project/find_lab) 中,这不是系统二进制文件或 man 页的标准位置。这说明了关键区别:对于你的个人文件或项目文件,请使用 findlocate;而对于调查系统命令,请使用 whereis

你现在已经学会了如何使用 whereis 快速定位构成 Linux 命令的文件,这对系统管理和故障排除非常有用。

使用 aliaswhichtype 分析命令路径

在最后这个步骤中,你将探索当你输入命令名称时,shell 是如何确定要执行哪个命令的。这并不总是像在磁盘上查找文件那么简单。Shell 有一个特定的优先级顺序:它首先检查 别名 (aliases),然后是 shell 内建命令 (shell built-in commands),最后搜索系统 $PATH 中的目录以查找可执行文件。你将学习使用 alias 创建命令快捷方式,以及使用 whichtype 来诊断命令名称实际指向什么。

让我们开始创建一个临时别名,看看它如何影响命令执行。我们将留在 ~/project 目录中。

  1. 别名是用户为另一个命令定义的快捷方式。让我们创建一个别名,使 pwd 命令(打印当前工作目录)改为执行 date 命令。
alias pwd='date'
  1. 现在,执行 pwd 命令。
pwd

它没有打印你的当前目录,而是打印了当前的日期和时间,因为别名具有更高的优先级。

<current date and time>

使用 whichtype 进行排查

现在,假设你不知道别名的存在。你会如何排查 pwd 出现异常行为的原因?这时 whichtype 就派上用场了。

  1. which 命令在 $PATH 环境变量列出的目录中查找可执行文件。
which pwd

输出将显示:

pwd: aliased to date
  1. type 命令更全面。它是一个 shell 内建命令,用于描述 shell 将如何解释命令名称,包括别名和内建函数。
type pwd

此命令会正确识别情况:

pwd is an alias for date
  1. 要查看匹配名称的所有可能命令,你可以使用 -a(all)标志。这对于 type 命令尤其强大。
type -a pwd

这将揭示 pwd 命令名称的完整层级结构:

pwd is an alias for date
pwd is a shell builtin
pwd is /usr/bin/pwd
pwd is /bin/pwd

此输出告诉你 shell 的首选顺序:它会首先使用别名。如果别名不存在,它将使用 shell 的内建 pwd 命令。如果两者都不存在,它将执行位于 /usr/bin/pwd 的程序。

删除别名

最后,让我们通过删除别名来清理我们的实验。

  1. unalias 命令会从当前 shell 会话中删除别名定义。
unalias pwd
  1. 现在,再次运行 pwdtype pwd 来确认一切都已恢复正常。
pwd

输出:

/home/labex/project
type pwd

输出:

pwd is a shell builtin

你现在已经学会了如何创建和删除别名,更重要的是,如何使用 whichtype 来准确理解 shell 将运行哪个命令。

总结

在本实验中,你学会了在 Linux 文件系统中搜索文件和目录。你从强大的 find 命令开始,使用基于名称的条件和通配符进行基本搜索,然后通过 -execxargs 进阶到对搜索结果执行命令。你还探索了 locate 命令,它是一个更快速、由数据库驱动的替代方案,并学会了如何使用 updatedb 来维护其数据库。

此外,本实验还涵盖了定位和分析命令的技术。你使用 whereis 来查找命令二进制文件及其手册页的位置。为了理解命令执行路径,你学会了使用 which 来识别正在调用的特定可执行文件,以及使用 type 来确定命令是别名、内建命令还是文件,同时还分析了别名如何影响命令行为。