拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux whereis命令完全指南:原理、参数与实战排坑

Linux whereis命令完全指南:原理、参数与实战排坑

前几天有同事拿着一个部署脚本问我,他在检测 Nginx 安装路径时,一会儿用which,一会儿用whereis,结果两个命令返回的路径对不上,脚本直接崩了。说实话这场景我太熟了,很多人在终端里敲了一两年 Linux,天天用which、find、locate,却一直没把whereis这个命令当回事。它看起来不起眼,实际却是“命令关联文件查询”里最对症的一个工具:一次返回命令的二进制文件、源代码文件和 man 手册页文件,而且速度极快,毫秒级出结果。

如果你正在准备 Linux 面试、写运维脚本,或者刚装完某个软件想搞明白它到底把文件都放到了哪里,这个命令值得花十分钟彻底学透。我会把它背后的工作原理、参数细节、实操场景和我踩过的坑都过一遍,看完你基本就能在日常工作里顺手用起来了。

1. 原理拆解:whereis 并不是普通搜索命令

1.1 它只回答一个核心问题:命令的相关文件在哪

你在终端里敲一个命令,比如ls,和它相关的文件其实不止一个,至少包含三类:

  • 真正能执行的二进制文件,一般是/usr/bin/ls或者/bin/ls;
  • 帮助手册 man page,通常是/usr/share/man/man1/ls.1.gz;
  • 如果系统带有配套源码,可能还会出现在/usr/src这类目录下。

whereis ls做的事,就是一次性把这三类结果全部列出来。我再强调一次:它只关心“命令相关文件”,不是“所有包含关键字的文件”。很多人抱怨whereis不好用,说找不到文件,其实是因为把它当成find来用了,理解错位了。

这个定位决定了它的价值。碰到环境排查时,你不仅要确认“命令能不能执行”,往往还想知道“文档在哪个目录”“有没有附带源码”,三个需求一条命令就能回答,这是which或者其他工具做不到的。

1.2 搜索机制:标准目录表加 PATH 叠加

whereis不需要像find那样递归遍历整个目录树。它自己维护了一张“默认搜索表”,我习惯叫它白名单。你可以用whereis -l把这张表完整打出来,一般会包含这几类路径:

  • 二进制目录:/usr/bin、/bin、/usr/sbin、/sbin、/usr/local/bin;
  • 手册目录:/usr/share/man、/usr/local/man、/usr/man;
  • 源码目录:/usr/src、/usr/local/src等。

注意,不同发行版默认的表略有区别,但大体围绕系统标准布局展开。这里有个很重要的细节:较新版本的 util-linux 中,whereis除了扫描这些标准目录,还会叠加当前 shell 的PATH环境变量。也就是说,如果你把软件装在了/opt/tool/bin,并且把这个目录加到了PATH,新版whereis是有可能扫到的。老版本则只认自己的默认表,扫不到很正常。网上关于“whereis 为什么查不到命令”的讨论特别多,十有八九就是版本和发行版差异造成的。

1.3 为什么它这么快

whereis的核心动作是“查名单”,不是“翻文件”。你要找nginx,它就把nginx这个名字放进预置目录里逐一比对,匹配到二进制就记一笔,匹配到手册再记一笔,全程不碰无关目录,所以能毫秒级返回。

打个比方:find像在大型仓库里逐层货架翻找,而whereis像前台拿着快递单号对照分配表,查到后直接告诉你包裹在哪个区哪个架。省时省力的同时,代价是它不认识不在分配表里的区域。

1.4 边界在哪里要心里有数

明确几个它做不到的事,能帮你少走弯路:

  • 不查普通数据文件和配置文件,/etc/nginx/nginx.conf这类文件不归它管;
  • 对 shell 别名和内建命令无能为力,alias ll、cd这种只能交给type;
  • 如果软件安装在完全自定义的目录下,且没进 PATH,新版不一定扫到,需要手动用-B参数指定目录。

理解这些边界,你对whereis的预期就会变得非常合理,不会产生“它怎么又找不到”的错觉。

2. 参数详解:五个核心选项彻底掌握

2.1 基本调用格式速记

whereis的格式很简单,一句话就能记住:

whereis [选项] 文件名1 文件名2 ...

注意这里传的是“文件名”,不是“路径”。你不该写whereis /usr/bin/cp,该写whereis cp。多个命令可以放在一起查,结果会按照顺序逐条列出。这条规则在写脚本时尤其重要,脚本里如果拿到的是完整路径,要先用basename拆出文件名再传进去。

2.2 -b、-m、-s:三类文件按需过滤

默认情况下三者全查。如果你只需要其中一种,就用过滤选项:

  • -b:只查二进制文件;
  • -m:只查 man 手册页;
  • -s:只查源码文件。

三个选项可以组合,比如whereis -bm curl就只关心二进制和手册。我平时写脚本时最常用-b,因为脚本里只需要可执行文件的绝对路径,不想被一堆 man 页面干扰。需要留意的是,输出里只有二进制而没有任何 man 页面时,不代表手册一定不存在,可能只是它的手册路径不在默认搜索表里,或者该命令的手册被放在了其他章节目录。

2.3 -u:帮你把“异常项”揪出来

-u的含义是“只显示那些没有满足常规完整条目的项”。什么是常规完整条目?一个正常安装的命令,通常应该同时具备二进制和 man 手册;如果某个命令只有二进制,却没有对应的手册,-u就会挑出来。

一个很实用的批量查法,是把它和/usr/bin/*组合使用:

whereis -u /usr/bin/*

这条命令能批量找出“装过了但缺少 man 帮助文档”的命令。第一次跑,你大概率会看到一批平时根本注意不到的“裸奔命令”。这个思路用在系统审计、文档整理、新环境验收上非常顺手。

2.4 -B、-M、-S 自定义搜索目录,以及必须交代的 -f

这是whereis最容易被忽略的功能。默认目录查不到时,可以手动指定搜索范围:

  • -B 目录列表:指定二进制搜索目录;
  • -M 目录列表:指定手册搜索目录;
  • -S 目录列表:指定源码搜索目录。

但这里面有一个非常容易踩的语法坑:当你用了这些大写选项时,后面的文件名列表必须用-f隔开。-f的作用是终止目录列表,告诉命令“接下来是文件名了”。举个例子:

whereis -B /opt/custom/bin /usr/local/bin -f mytool

意思是在/opt/custom/bin和/usr/local/bin里找mytool的二进制文件。如果不写-f,命令会把mytool当成目录继续解析,要么报错,要么返回空结果。我第一次用的时候就栽在这上面,折腾了半天才发现少写了一个-f。

2.5 辅助选项:-l、-h、-V

-l用于列出默认搜索目录,调试 environment 时非常有用。-h和-V分别是帮助和版本信息,但不同发行版对这两个短选项的兼容性不太一样,有的版本不支持-h,会提示 invalid option。遇到这种情况,改用whereis --help或whereis --version,或者直接man whereis,都没问题。

3. 实战演示:三个场景加一段面试考点

3.1 场景一:一次性体检基础命令

假设你要确认一台新装的服务器上核心命令是否齐全,手册是否也都装好了,可以这样:

whereis ls cp mv rm cat grep awk sed tar

在标准系统上,输出大致长这样(不同发行版略有差异):

ls: /usr/bin/ls /usr/share/man/man1/ls.1.gz cp: /usr/bin/cp /usr/share/man/man1/cp.1.gz mv: /usr/bin/mv /usr/share/man/man1/mv.1.gz rm: /usr/bin/rm /usr/share/man/man1/rm.1.gz cat: /usr/bin/cat /usr/share/man/man1/cat.1.gz grep: /usr/bin/grep /usr/share/man/man1/grep.1.gz awk: /usr/bin/awk /usr/share/man/man1/awk.1.gz sed: /usr/bin/sed /usr/share/man/man1/sed.1.gz tar: /usr/bin/tar /usr/share/man/man1/tar.1.gz

一眼扫过去,二进制都在,手册也都在,说明这套环境的基础命令安装得很完整。如果哪一行只有/usr/bin/xxx而没有.gz文档,说明该命令的文档包没装,最常见的原因是最小化安装时没勾选man-pages。

3.2 场景二:只想拿 man 手册路径

写内部技术文档或者做离线帮助中心时,我经常只关心手册文件位置。比如要确认git的手册都在哪:

whereis -m git

输出会列出所有和git相关的 man 手册路径,包括git.1.gz、gitattributes.5.gz等。这个结果可以直接用于脚本打包手册目录,也可以用来做文档索引。如果没有-m过滤,输出里会混进/usr/bin/git,处理起来反而不方便。

3.3 场景三:给自定义安装的软件做定位

我之前在/opt/myservice/bin下装过一个内部工具svcctl,默认whereis svcctl半天没反应。这时用-B手动圈定目录:

whereis -B /opt/myservice/bin -f svcctl

返回:

svcctl: /opt/myservice/bin/svcctl

如果工具还自带了手册在/opt/myservice/man,还可以一并指定:

whereis -B /opt/myservice/bin -M /opt/myservice/man -f svcctl

这个组合能力让whereis在五花八门的自定义安装场景里也能派上用场。注意大写参数不能重复出现,例如不能写成-B /a -B /b,要把多个目录一次列全:-B /a /b /c。

3.4 面试官常问的几个 whereis 考点

结合这几年看面试题的经验,关于whereis的高频追问几乎集中在下面几个问题:

  • whereis和which有什么区别?核心回答:which只按PATH找第一个可执行文件;whereis基于默认标准目录查找二进制、man 手册和源码三类关联文件,新版还会叠加PATH。
  • whereis的原理是什么?核心回答:不遍历全盘,基于默认目录列表查询,可以用-l查看表。
  • 为什么刚编译安装的命令whereis找不到?核心回答:自定义安装目录不在默认表;用-B指定。
  • shell 内建命令能查吗?核心回答:查不了,得用type。

这些点准备到位,面试时被问到相关概念基本不会卡壳。

4. 常见问题与排查:明明有,为什么查不到

4.1 命令明明能用,whereis 却返回空

优先级最高的原因是“目录不在搜索列表里”。whereis的默认目录表不等于你的PATH。如果你是通过源码编译,把命令手动放进了/usr/local/xxx,而新版whereis又没覆盖到该目录,它查不到很正常。

排查分三步走:第一步,用which cmd看命令实际路径;第二步,用echo $PATH对比哪些目录是后加的;第三步,用whereis -B <实际目录> -f cmd手动测试,如果这样能查到,说明就是默认表的问题。如果脚本里需要稳定使用whereis,最好显式带-B参数,不要依赖环境差异。

第二个原因是“它不是真的命令”。敲whereis cd大概率空结果,因为cd是 shell 内建命令,文件系统里没有对应的可执行文件。同样,whereis ll查不到也很正常,因为ll通常是ls -l的别名。这种场景改用type cd或者type ll看真实身份。

第三个原因相对隐蔽:命令安装后PATH还没刷新。有些安装脚本只改了/etc/profile,当前会话没有执行source,此时which也未必正确。但whereis因为还查默认目录,偶尔反而能给出老版本路径,这就是开头同事遇到“两个命令对不上”的常见来源。

4.2 返回结果里有重复路径

在部分系统上,你会看到/bin/xxx和/usr/bin/xxx同时出现。这多半是因为/bin是/usr/bin的符号链接,whereis同时命中了两个入口。不算错误,只是它非常诚实地列出了所有能匹配的路径。

解析结果时,只取第一个匹配项就好。比如脚本里用whereis -b cmd获取输出后,通过awk '{print $2}'拿第一个路径字段,第一个字段是“命令名:”。如果想规避符号链接,再加一步readlink -f做路径归一化。

要特别提一个现象:whereis偶尔会返回共享库文件路径。比如whereis curl在某些系统上会带上/usr/lib/x86_64-linux-gnu/libcurl.so.4这样的条目。因为/usr/lib目录也可能被纳入二进制搜索范围,库里恰好有和命令名相关的文件。处理脚本时要做好心理准备,别把每条结果都当成“可执行文件”。

4.3 man 手册一直缺失

二进制能找到但手册死活没有,最常见原因是系统没装man-pages或对应的xxx-doc包。Linux 的命令手册经常拆成独立软件包维护,比如 Debian 系下,git的手册可能在git-man包里。

另一个原因是手册目录不在whereis默认表里。你可以先执行man -w 命令名,拿到 man 实际搜索路径,如果路径确实存在而whereis -m查不到,说明它没收录该目录。此时手动用-M <路径> -f 命令名验证即可。

4.4 把路径和文件名搞混了

很多人写whereis /usr/bin/python3,然后返回空,原因很简单:whereis期待的是名字,不是带完整路径的文件。如果你传了绝对路径,它的匹配逻辑会出错,大多数版本直接返回空。

正确姿势是whereis python3,再从结果里挑路径。这条规则写在脚本里尤其重要,从配置里拿到完整路径去查文档时,得先拆出目录和文件名,用文件名去查。

4.5 不同发行版行为不一致

CentOS 7 和 Ubuntu 22.04 自带的whereis版本不同,选项支持、默认目录表、是否叠加PATH都不是完全一致的。跨多套环境跑脚本时,建议先加一步whereis -l | head -5的日志输出,让系统自己交代它的搜索范围。必要时按发行版走不同分支,别拿一套逻辑硬套所有机器。

5. 和 which、type、find、locate 对比:一张表看懂选型

5.1 核心差异对照

很多新手问:我已经有which了,为什么还要学whereis?其实它们根本不是同一层面的工具。我把常用查找类命令放在一起对比:

命令搜索来源典型返回常用场景
whereis系统标准目录 + 部分新版叠加 PATH二进制、源码、man 手册页查命令关联文件、批量审计
which当前 shell 的 PATH第一个匹配的可执行文件路径确认敲命令时会执行哪个
typeshell 语义(别名、内建、函数、外部命令)命令的真实类型和定义排查别名、内建命令
find实时遍历指定目录目录树中所有匹配文件精确查找任意文件
locate预生成文件数据库全库文件名匹配项快速全盘搜索已知文件名

光看表不够,实际差异往往体现在具体问题里。which git回答的是“当前环境会运行哪个 git”;whereis git回答的是“git 的二进制、手册、源码分别在哪”;type git回答的是“git 是外部命令还是函数”;find / -name git回答的是“全盘里所有叫 git 的文件”。四个工具回答的是四个完全不同的问题。

5.2 实际中我这样选

写脚本判断命令是否存在,我会用command -v golang这种 POSIX 标准写法,或者 Bash 里的type -P golang,用途是“确保能执行”。需要收集完整装配信息时,比如生成系统文档、做依赖清单,我会用whereis -b 命令名,把每个命令的绝对路径都捞出来。想查配置文件、日志文件、数据文件时,whereis和which都帮不上忙,交给find或locate才是正道。

which并没有被淘汰。它轻量、快速、输出干净,在交互式终端里给人看最直接。whereis的输出格式适合脚本解析,但字段在不同系统上会有噪音,交互场景反而不如which干净。这也是很多老手的肌肉记忆里,终端里直接敲的是which,脚本批量处理时却转身去用whereis或command -v。

6. 实战心得:我踩过的三个坑和三个建议

6.1 踩坑一:以为 whereis 会自动跟踪 PATH,结果拿到旧路径

有次我从源码编译安装了新版vim,装到了/usr/local/bin,PATH里也是这个目录优先,敲vim用的是新版本。但whereis vim返回的却是/usr/bin/vim,因为默认表里优先匹配了系统自带路径。那一刻我才彻底明白:不能默认whereis跟随PATH,它的标准路径优先级很高。如果脚本里要拿“真正会执行的命令路径”,先command -v再readlink -f,才是最稳的组合。

6.2 踩坑二:把 -f 写丢

用-B指定目录时,我刚开始总忘记写-f,命令要么输出空,要么把文件名当目录名继续找。后来养成一个条件反射:但凡看到大写选项-B、-M、-S,脑子里自动配对——后面一定跟一个-f,再后面才是文件名。不确定时就用man whereis反复确认,别凭记忆写。

6.3 踩坑三:结果里的 .so 文件被脚本误判

做“服务可执行文件路径收集”脚本时,whereis -b返回了匹配的共享库路径,脚本顺手把它当成二进制拿去启动,踩了个不大不小的坑。从那以后,我的解析规则变成:只从结果里取/usr/bin、/usr/local/bin这类以bin结尾的真实可执行路径,其他一律跳过,再配合file命令验证可执行类型。这条规则在跨发行版场景下尤其重要。

6.4 三个实用建议

第一,用whereis -b代替裸的whereis作为脚本输入。默认输出会混入手册页和源码路径,字段多、噪音大,加-b之后干净得多。

第二,用whereis -m做文档完整性检查。新环境验收时,跑一遍whereis -m curl wget tar git,哪些手册缺失一眼便知。配合-u做批量审计,能把“缺少帮助文档的命令”成批抓出来。

第三,把whereis当作理解程序安装布局的起点。查到路径之后,顺着dirname再去翻docs、share、etc等兄弟目录,往往能比纯find更快摸清一个陌生软件的安装全貌。这个思路在接手不熟悉的环境时特别实用,能帮你快速建立整个系统的软件分布地图。

我在实际使用中的整体感受是:whereis不是一个全能搜索器,但它在“查询命令关联文件”这件事上做到了一次到位、速度快、输出可解析。学会它之后,我的终端里少了很多为找文档而反复敲find的多余操作。如果你之前一直把它晾在一边,现在花几分钟把它纳入自己的常用工具箱,后续排查环境时会爽快不少。

返回列表