which 返回 PATH 中第一个匹配的可执行文件路径,只检查 PATH 目录中是否存在同名可执行文件,找到即停;它不处理 alias、function 或 shell builtin,结果反映实际运行的命令路径。

which 返回的是 PATH 中第一个匹配的可执行文件路径
它只看 PATH 环境变量里列出的目录,挨个检查有没有同名的可执行文件,找到第一个就停。所以结果反映的是“你敲这个命令时,系统实际会运行哪一个”。
常见错误现象:
-
which python找不到,但python --version能跑 → 很可能是 alias 或 shell function 干扰,不是真没装 -
which ls返回/bin/ls,但ls实际是 alias →which不处理 alias,得用type ls看真实类型 - 用户自己编译安装的程序没加到
PATH里,which就完全看不见
实操建议:
- 查多个同名命令:用
which -a python,它会把PATH里所有匹配的都列出来 - 脚本中判断命令是否存在:直接
if command -v git >/dev/null; then ...比which更可靠(command -v是 POSIX 标准,兼容性更好) - 别依赖
which判断是否安装了某个包 —— 它只管路径,不管包管理器状态
whereis 查的是命令在系统标准位置留下的“痕迹”
whereis 不走 PATH,而是固定扫描几个系统目录,比如 /usr/bin、/usr/share/man、/usr/src,找二进制、手册页、源码三类东西。它的结果不是“运行时用哪个”,而是“这个命令在系统里还存了哪些配套文件”。
常见错误现象:
-
whereis nginx返回空或只有冒号nginx:→ 基本说明没装,或者装在非标路径(如/opt/nginx),whereis默认不扫那里 -
whereis -m gcc找不到手册页 → 可能只装了gcc,没装gcc-doc或对应 man 包 - 刚
apt install一个新命令,whereis还查不到 → 它不实时扫描,依赖系统维护的索引,但不像locate那样需要手动updatedb,一般随系统更新自动刷新
实操建议:
- 想快速打开某命令的手册页:先
whereis -m curl,再man /usr/share/man/man1/curl.1.gz - 确认开发头文件或库路径:
whereis -b -m -s openssl,一次看到二进制、man、源码位置(虽然源码通常不装) - 缩小搜索范围提速:用
-B /usr/local/bin -f node限定只在/usr/local/bin里找node的二进制
which 和 whereis 结果不一致时,该信谁?
这不是 bug,是设计目标不同。比如:
-
which pip返回/home/user/.local/bin/pip(用户本地安装) -
whereis pip返回pip: /usr/bin/pip /usr/share/man/man1/pip.1.gz(系统包管理器装的)
这时候说明你有两个 pip:一个在用户目录,一个在系统目录;which 告诉你当前生效的是哪个,whereis 告诉你系统里还存着另一个的文档和二进制。
容易踩的坑:
- 用
whereis的路径去改权限或删文件 → 可能删掉的是系统版本,而你日常用的其实是用户版 - 看到
which找不到就断定“没装”,忽略 alias / function / shell builtin 的可能 - 在 CI/CD 脚本里用
whereis判断工具可用性 → 它可能返回旧路径,或根本没结果,不如用command -v+--help实际调用验证
真正要解决“这个命令在哪”,还得看上下文
如果你只是想确认终端里敲的 git 是哪个文件,which git 够用;但如果你在调试编译失败,发现 make 报错说找不到 cc,就得先 which cc 看它指向哪,再 whereis -m cc 看手册是否齐全,甚至 readlink -f $(which cc) 看是不是符号链接跳转到了别的编译器。
复杂点在于:shell builtin(如 cd)、alias(如 ll='ls -l')、function、符号链接、PATH 顺序、用户 vs 系统安装路径 —— 这些都会让“一个命令对应多个路径”成为常态。别指望单个命令覆盖全部场景。


















