首页 > Sysadmin > 正文

Linux 查找命令所在路径完整指南:which、whereis 与 type

huyuanwen 2026-11-05 Sysadmin

草稿待审:locate (plocate) 本机无索引数据库,基于文档核查,尚未实际执行;rpm -qf 为 RPM 系发行版命令,本机 Ubuntu 未安装 rpm,基于文档核查;其余命令 (which、whereis、type、command -v、readlink、realpath、find、dpkg -S) 均在 WSL2 Ubuntu 24.04 实测通过。

在 Linux 上定位命令的可执行文件路径,不同工具的搜索范围与输出格式差异很大。

选错工具会得到别名定义、符号链接或手册页路径,而非真正执行的二进制。本文按命令类型分场景,给出可直接运行的命令与预期输出。

命令类型与选型对照

Shell 会按固定顺序解析命令:别名 → 关键字 → 函数 → 内建命令 → PATH 中的外部可执行文件 [3]。不同定位工具覆盖的范围不同:

命令类型 推荐工具 典型输出
别名 type / command -v alias ll='ls -l'
Shell 内建 type / command -v cd is a shell builtin
Shell 函数 type / command -v 函数定义
外部可执行文件 which / type -P / command -v /usr/bin/ls
符号链接目标 readlink -f / realpath /usr/bin/python3.12
包归属 (Debian/Ubuntu) dpkg -S <绝对路径> coreutils: /usr/bin/ls
包归属 (RPM 系) rpm -qf <绝对路径> coreutils-... (基于文档核查)

which 与 whereis

which 只在 PATH 中搜索可执行文件,不识别别名或函数,也不解析符号链接 [1]。

whereis 搜索二进制、源码与手册页,范围比 which 更广 [2]:

which ls
which -a sh
whereis ls
whereis -b ls
whereis -m ls
  • which ls 输出 /usr/bin/ls
  • which -a sh 列出 PATH 中所有同名可执行文件,如 /usr/bin/sh 与 /bin/sh
  • 退出码:0 全部找到,1 有未找到,2 选项非法 [1]
  • whereis ls 输出 ls: /usr/bin/ls /usr/share/man/man1/ls.1.gz
  • -b 仅二进制,-m 仅手册页,-s 仅源码
  • 可用 -B/-M/-S 指定额外搜索目录,-f 终止目录列表 [2]

type 与 command -v

type 是 Bash 内建,能识别别名、关键字、函数、内建与外部命令 [3]。command -v 与 command -V 用于脚本中判断命令类型 [3]:

type ls
type cd
type if
shopt -s expand_aliases
alias ll='ls -l'
type ll
type -P ls
command -v ls
command -v cd
command -V ls
  • type ls → ls is /usr/bin/ls
  • type cd → cd is a shell builtin
  • type if → if is a shell keyword
  • type ll → ll is aliased to 'ls -l'
  • type -P ls → /usr/bin/ls(仅输出 PATH 中的外部命令路径,别名/函数返回空)
  • command -v ls → /usr/bin/ls
  • command -v cd → cd(内建命令只输出名称)
  • command -V ls → ls is /usr/bin/ls(更详细的描述)

脚本中推荐用 command -v 做存在性检查,因为它对别名、内建、外部命令都有效且输出稳定。

readlink 与 realpath

当命令是符号链接时,which 只给出链接路径,需用 readlink 或 realpath 解析到真实文件 [4][5]:

readlink -f /usr/bin/python3
realpath /usr/bin/python3
readlink -e /tmp/nonexistent 2>/dev/null; echo "exit=$?"
  • readlink -f 逐级解析所有符号链接,最终文件不存在时仍输出推导路径
  • readlink -e 要求最终文件存在,否则输出空并返回非零
  • realpath 默认行为等同 readlink -f;realpath -e 等同 readlink -e
  • 实测:/usr/bin/python3 → /usr/bin/python3.12

全盘搜索与包归属

PATH 之外的文件用 find 或 locate 搜索 [6][7];已知绝对路径可反查所属包 [8]:

find /usr/bin -maxdepth 1 -name 'ls' -type f
locate -l 5 ls
dpkg -S /usr/bin/ls
dpkg -L coreutils | grep -E '/ls$'
  • find 直接遍历目录,无需索引,适合精确搜索
  • locate 依赖 updatedb 构建的索引,查询极快但无法找到索引更新后新增的文件;本机无索引数据库,该命令基于文档核查 [7]
  • dpkg -S /usr/bin/ls → coreutils: /usr/bin/ls
  • dpkg -L coreutils 列出包内所有文件

RPM 系发行版 (CentOS/RHEL/Fedora) 对应命令为 rpm -qf /usr/bin/ls [9],本机 Ubuntu 未安装 rpm,该命令基于文档核查。

排错速查表

现象 原因 处理
which 找不到已安装命令 PATH 未包含该目录或 shell 未刷新 echo $PATH;hash -r 清除命令缓存后重试
type 报 not found 但命令可运行 别名未在非交互 shell 展开 脚本中用 shopt -s expand_aliases 或改用 command -v
readlink -f 输出路径但文件不存在 链接链断裂或目标被删除 改用 readlink -e 校验最终文件存在
locate 无输出或报数据库缺失 未运行 updatedb sudo updatedb 后重试,或改用 find
dpkg -S 返回大量不相关结果 传入的是文件名而非绝对路径 务必传绝对路径,如 /usr/bin/ls
which -a 与 type -a 结果不同 which 不识别别名/函数 需要覆盖别名/函数时用 type -a

附录

  • 测试机:WSL2 Ubuntu 24.04.4 LTS
  • 内核:Linux 6.6.114.1-microsoft-standard-WSL2
  • 测试日期:2026-11-05
  • 观察结果:which ls → /usr/bin/ls;which -a sh → /usr/bin/sh 与 /bin/sh;whereis ls → /usr/bin/ls /usr/share/man/man1/ls.1.gz;type ls/cd/if 分别输出外部/内建/关键字;别名在 shopt -s expand_aliases 下被 type 与 command -v 正确识别;type -P 对别名返回空;readlink -f 与 realpath 均将 /usr/bin/python3 解析为 /usr/bin/python3.12;find /usr/bin -maxdepth 1 -name 'ls' → /usr/bin/ls;dpkg -S /usr/bin/ls → coreutils: /usr/bin/ls;locate 因无索引数据库未实测;rpm 未安装未实测。
  • 本文所有命令均为只读查询,不修改系统,无需回滚。

常见问题

  • 问:脚本里该用 which 还是 command -v?

优先 command -v。它覆盖别名、内建、函数与外部命令,输出更稳定;which 仅搜索 PATH 且在部分发行版上是外部脚本,行为略有差异。

  • 问:readlink -f 和 realpath 有什么区别?

日常用途等价。realpath 来自 coreutils,选项更丰富(如 -m 允许路径不存在);readlink 来自 util-linux,-e/-f 语义清晰。两者都比 ls -l 解析链接更可靠。

  • 问:如何确认命令到底执行了哪个文件?

用 type -a <命令> 查看全部候选,再用 readlink -f $(type -P <命令>) 解析符号链接。type -P 确保只取 PATH 中的外部命令,避免别名干扰。

  • 问:locate 找不到刚安装的程序怎么办?

运行 sudo updatedb 更新索引,或改用 find / -name '<文件名>' 2>/dev/null 直接遍历。

  • 问:如何从命令反查安装包?

Debian/Ubuntu 用 dpkg -S $(readlink -f $(type -P <命令>));RPM 系用 rpm -qf $(readlink -f $(which <命令>))。务必传绝对路径。


参考资料

文中主要命令已在 WSL Ubuntu(24.04)实测并核对其在 Debian 系与通用发行版的文档口径。