[小技巧39]Linux 文件与命令查找工具(which、whereis、locate、find)全面解析

一、核心命令对比

命令 主要用途 搜索范围 是否依赖数据库 支持通配符/正则 执行速度 典型使用场景
which 查找可执行命令路径 $PATH 环境变量中的目录 否(仅精确匹配) 极快 确认命令是否可用及具体路径
whereis 查找二进制、源码、手册页位置 预定义系统目录(非 $PATH 快速获取程序相关文件位置
locate 快速模糊查找文件名 全系统(基于 updatedb 数据库) 支持通配符 极快 忘记确切路径但记得部分文件名
find 强大灵活的实时文件搜索 指定目录树(默认递归) 支持通配符与正则 较慢 精确条件搜索(如按时间、权限、类型等)

注意locate 的数据库通常由 cron 每日更新(如 /etc/cron.daily/mlocate),新创建的文件需手动运行 sudo updatedb 才能被索引。

二、各命令详解与示例

1. which

  • 作用 :在 $PATH 中查找可执行文件。

  • 特点 :只返回第一个匹配项(除非加 -a 显示所有)。

  • 示例

    bash 复制代码
    which python3
    # 输出:/usr/bin/python3
    
    which -a gcc
    # 显示所有名为 gcc 的可执行文件路径

2. whereis

  • 作用:查找二进制文件、源代码和 man 手册的位置。

  • 特点 :不搜索 $PATH,而是使用硬编码的系统路径。

  • 示例

    bash 复制代码
    whereis nginx
    # 输出:nginx: /usr/sbin/nginx /usr/share/man/man8/nginx.8.gz

3. locate

  • 作用:通过预建数据库快速查找文件名(支持模糊匹配)。

  • 依赖包 :通常为 mlocateplocate

  • 示例

    bash 复制代码
    locate docker-compose.yml
    # 返回所有匹配文件路径
    
    locate -i "*.LOG"
    # 忽略大小写查找 .LOG 文件

4. find

  • 作用:在指定目录中实时遍历并按条件筛选文件。

  • 功能最全:支持按名称、类型、大小、修改时间、权限、属主等过滤。

  • 示例

    bash 复制代码
    # 查找当前目录下所有 .log 文件
    find . -name "*.log"
    
    # 查找 7 天内修改过的 .conf 文件
    find /etc -name "*.conf" -mtime -7
    
    # 删除空目录
    find /tmp -type d -empty -delete

5. 关于whereis查询不使用本地数据库的证明

证明1

shell 复制代码
root@root:~# touch /usr/local/unique_test_file_xyz123
root@root:~# updatedb
/usr/bin/find: '/run/user/128/doc': Permission denied
/usr/bin/find: '/run/user/1000/gvfs': Permission denied
/usr/bin/find: '/run/user/1000/doc': Permission denied
root@root:~# 
root@root:~# 
root@root:~# 
root@root:~# locate unique_test_file_xyz123
/usr/local/unique_test_file_xyz123
root@root:~# whereis unique_test_file_xyz123
unique_test_file_xyz123: /usr/local/unique_test_file_xyz123
root@root:~# rm /usr/local/unique_test_file_xyz123
root@root:~# locate unique_test_file_xyz123
/usr/local/unique_test_file_xyz123
root@root:~# whereis unique_test_file_xyz123
unique_test_file_xyz123:

观察到的现象

  • 文件存在时:locate 和 whereis 都能找到
  • 删除文件后:locate 仍能找到(数据库未更新),但 whereis 找不到

证明2

shell 复制代码
root@root:~# cat whereis.sh
#!/bin/bash
echo "=== 验证 whereis 是否实时检查文件 ==="

# 创建测试文件
TEST_FILE="/usr/local/verify_$$.txt"
sudo touch "$TEST_FILE"
sudo updatedb

echo "1. 文件存在时:"
echo "   locate: $(locate verify_$$.txt | head -1)"
echo "   whereis: $(whereis verify_$$.txt | awk '{print $2}')"

# 使用 strace 查看系统调用
echo -e "\n2. 跟踪 whereis 的系统调用:"
strace -e trace=file whereis verify_$$.txt 2>&1 | tail -10

# 删除文件
sudo rm "$TEST_FILE"

echo -e "\n3. 文件删除后:"
echo "   locate(数据库未更新): $(locate verify_$$.txt | head -1)"
echo "   whereis(实时检查): $(whereis verify_$$.txt | awk '{print $2}')"

echo -e "\n4. 再次跟踪 whereis:"
strace -e trace=file whereis verify_$$.txt 2>&1 | tail -10
~                                                                                                    
~                                                                                                    
#输出结果
root@root:~# bash whereis.sh
=== 验证 whereis 是否实时检查文件 ===
/usr/bin/find: '/run/user/128/doc': Permission denied
/usr/bin/find: '/run/user/1000/gvfs': Permission denied
/usr/bin/find: '/run/user/1000/doc': Permission denied
1. 文件存在时:
   locate: /usr/local/verify_482343.txt
   whereis: /usr/local/verify_482343.txt

2. 跟踪 whereis 的系统调用:
openat(AT_FDCWD, "/usr/src/linux-hwe-6.8-headers-6.8.0-88", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=4096, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/src/linux-hwe-6.8-headers-6.8.0-90", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=4096, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/src/python3.10", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=4096, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/src/linux-headers-6.8.0-90-generic", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=4096, ...}, AT_EMPTY_PATH) = 0
verify_482343.txt: /usr/local/verify_482343.txt
+++ exited with 0 +++

3. 文件删除后:
   locate(数据库未更新): /usr/local/verify_482343.txt
   whereis(实时检查): 

4. 再次跟踪 whereis:
openat(AT_FDCWD, "/usr/src/linux-hwe-6.8-headers-6.8.0-88", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=4096, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/src/linux-hwe-6.8-headers-6.8.0-90", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=4096, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/src/python3.10", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=4096, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/src/linux-headers-6.8.0-90-generic", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=4096, ...}, AT_EMPTY_PATH) = 0
verify_482343.txt:
+++ exited with 0 +++

whereis 的工作方式:

  • 不使用 locate 数据库(从 strace 看,它确实没有打开 /var/cache/locate/locatedb)
  • 在预定义的硬编码目录列表中查找
  • 对每个可能的路径进行实时 stat() 检查

预定义目录包括:

二进制目录:/bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin 等

手册页目录:/usr/share/man, /usr/local/man 等

源代码目录:/usr/src, /usr/local/src 等

证明3

shell 复制代码
root@root:~# cat whereis_1.sh 
#!/bin/bash
echo "=== 测试 whereis 的默认搜索模式 ==="

# 查看 whereis 默认搜索什么
man whereis | grep -A5 "DESCRIPTION"

# 测试不同选项
echo -e "\n1. 默认搜索(二进制+手册+源码):"
whereis ls

echo -e "\n2. 只搜索二进制文件:"
whereis -b ls

echo -e "\n3. 只搜索手册页:"
whereis -m ls

echo -e "\n4. 只搜索源代码:"
whereis -s ls

# 创建测试文件测试
echo -e "\n5. 测试新文件:"
TEST_FILE="/usr/local/testcmd_$$"
sudo touch "$TEST_FILE"
sudo chmod +x "$TEST_FILE"
sudo updatedb

echo "   默认搜索: $(whereis testcmd_$$)"
echo "   只搜二进制: $(whereis -b testcmd_$$)"
                                                     
# 输出结果
root@root:~# bash whereis_1.sh
=== 测试 whereis 的默认搜索模式 ===
DESCRIPTION
       whereis locates the binary, source and manual files for the specified command names. The
       supplied names are first stripped of leading pathname components. Prefixes of s. resulting
       from use of source code control are also dealt with. whereis then attempts to locate the
       desired program in the standard Linux places, and in the places specified by $PATH and
       $MANPATH.

1. 默认搜索(二进制+手册+源码):
ls: /usr/bin/ls /usr/share/man/man1/ls.1.gz

2. 只搜索二进制文件:
ls: /usr/bin/ls

3. 只搜索手册页:
ls: /usr/share/man/man1/ls.1.gz

4. 只搜索源代码:
ls:

5. 测试新文件:
/usr/bin/find: '/run/user/128/doc': Permission denied
/usr/bin/find: '/run/user/1000/gvfs': Permission denied
/usr/bin/find: '/run/user/1000/doc': Permission denied
   默认搜索: testcmd_483961: /usr/local/testcmd_483961
   只搜二进制: testcmd_483961: /usr/local/testcmd_483961

whereis 的官方描述中的关键点

  • 明确说明查找二进制、源代码和手册文件
  • 在标准 Linux 位置查找
  • 也使用 PATH 和 MANPATH 环境变量

whereis 的实际工作机制

bash 复制代码
# whereis 的搜索逻辑简化版
1. 解析命令行选项 (-b, -m, -s)
2. 确定要搜索的目录列表:
   - 二进制目录:$PATH 中的目录 + 标准目录 (/bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, ...)
   - 手册页目录:$MANPATH 中的目录 + 标准目录 (/usr/share/man, /usr/local/man, ...)
   - 源代码目录:标准目录 (/usr/src, /usr/local/src, ...)
3. 在这些目录中递归搜索指定文件名
4. 对找到的文件进行类型判断和分类
5. 输出结果

与 locate 的根本区别

特性 whereis locate
数据源 实时搜索预定义目录 预构建的完整文件系统数据库
搜索范围 有限的标准目录 整个文件系统(排除的除外)
实时性 实时 非实时(依赖数据库更新)
用途 查找命令相关文件 查找任何文件
性能 较快(搜索有限目录) 很快(数据库查询)

证明 whereis 不使用数据库的关键证据

  1. 即时性whereis 在文件创建后立即能找到(虽然运行了 updatedb,但即使不运行,如果文件在标准目录中,whereis 也能找到)
  2. 有限范围whereis 只能找到标准位置的文件
  3. 手册页明确说明:在"标准 Linux 位置"查找

最终结论

whereis 的本质:

  1. 不是数据库搜索工具 ,而是目录扫描工具
  2. 预定义的标准目录集合中搜索
  3. 使用 PATH 和 MANPATH 环境变量扩展搜索范围
  4. 进行实时文件系统访问,不是查询数据库

三、其他相关命令

命令 说明
type Shell 内置命令,判断命令类型(别名、函数、内置、外部程序)。示例:type lsls is aliased to 'ls --color=auto'
command 跳过别名和函数,直接调用可执行文件。示例:command ls(绕过别名)
whatis 显示命令的简短描述(来自 man 页面的第一行)。示例:whatis curlcurl (1) - transfer a URL
apropos 按关键词搜索 man 手册页(等价于 man -k)。示例:apropos "copy file"

四、使用决策建议

场景 推荐命令
"这个命令在哪?" which(确认是否在 PATH 中)或 type(更准确识别类型)
"这个软件有哪些相关文件?" whereis
"我记得文件名里有 'config',但不知道在哪" locate config(确保数据库已更新)
"找最近 1 小时修改的日志文件" find /var/log -name "*.log" -mmin -60
"找大于 1GB 的文件" find / -type f -size +1G
"查某个命令是别名还是真实程序" type command_name

五、总结

  • 速度优先 → 用 locate(但注意数据时效性)。
  • 精确控制 → 用 find(功能最强,但较慢)。
  • 查可执行命令 → 优先 whichtype
  • 查程序全家桶(bin/man/src)whereis
相关推荐
xlq223222 小时前
6.Linux权限
linux
ayaya_mana2 小时前
在 CentOS 7/RHEL 7 上安装并切换至新版内核
linux·运维·centos
三不原则2 小时前
故障案例:数据库慢查询导致交易延迟,AIOps 如何自动定位?
运维·数据库
gzxx2007sddx2 小时前
ubuntu挂载访问windows的共享文件夹
linux·运维·ubuntu·挂载·共享
市安2 小时前
基于 LVS+Keepalived+NFS 的高可用 Web 集群构建与验证
运维·服务器·网络·lvs·keepalived·ipvsadm
AC赳赳老秦3 小时前
Dify工作流+DeepSeek:运维自动化闭环(数据采集→报告生成)
android·大数据·运维·数据库·人工智能·golang·deepseek
真的想上岸啊3 小时前
4、修改开发板内核启动日志级别
linux
RisunJan3 小时前
Linux命令-kill(向进程发送信号的核心命令)
linux·运维·服务器
物理与数学3 小时前
linux内核 页缓存的脏页管理
linux·linux内核