很多人第一次看到根目录都会懵:
/bin
/sbin
/usr/bin
/usr/sbin
直觉会觉得:这肯定是精心设计 过的分层结构。
系统命令、用户命令、管理命令、扩展命令......听起来很合理。
但真正的答案是:
这不是设计,这是 50 年历史叠加出来的"化石结构"。
而这个真相,来自 BusyBox 核心开发者 Rob Landley 在 2010 年邮件列表里的一段吐槽。
一个连 BusyBox 作者都看不懂的目录规则
Rob 当时在做 BusyBox 链接布局时,发现一件非常离谱的事:
为什么
kill在/bin,而killall却在/usr/bin?到底有没有一条明确规则能解释这些目录?
结论是:没有。
这背后不是逻辑,而是历史偶然。
故事要从 1970 年代说起
Unix 诞生在 PDP-11 上。
那时候的硬盘有多大?
1.5MB。
不是 GB,是 MB。
整个系统最初都装在根文件系统 / 里:
/bin 基本命令
/sbin 系统管理命令
/lib 库
后来系统越写越大,一块盘装不下了。
怎么办?
加第二块盘。
但 Unix 没有 C 盘 D 盘的概念,第二块盘被挂载到 /usr。
于是世界开始分裂了:
/bin 在第一块盘
/usr/bin 在第二块盘
关键规则(当年非常重要)
当时形成了一条非常清晰、非常有意义的规则:
系统早期启动必须用到的命令 → /bin、/sbin
挂载 /usr 之后才需要的命令 → /usr/bin、/usr/sbin
这解决了一个真实存在的"先有鸡还是先有蛋"的问题:
你需要
mount才能挂载第二块磁盘,但如果
mount在第二块磁盘里,你就永远挂不上它 😂
所以:
mount → /bin
其他不重要的命令 → /usr/bin
在 1970 年代,这是非常聪明、非常必要的设计。
为什么这套规则今天已经失去意义?
1️⃣ 现代系统有 initramfs
现在内核启动后,会先进入一个临时根文件系统(initramfs)。
所有"早期启动需要的东西",都在这里解决了。
不再需要通过目录结构区分启动阶段。
2️⃣ 共享库的出现,打破了"独立性"假设
早期 Unix 程序是完全静态链接的:
ls 里有一份 printf
cp 里有一份 printf
mv 里也有一份 printf
这意味着:
/bin 和 /usr/bin 的程序可以完全独立存在
来自不同磁盘、不同版本、不同系统
这正是目录分离的技术前提。
但有了共享库之后:
/bin/ls 依赖 /usr/lib/libc.so.6
如果库版本不匹配,程序直接无法运行。
从这一刻开始:
/bin、/usr/bin、/lib、/usr/lib
已经不可能再被当成"可以独立升级、独立存在"的部分。
而目录结构,正是建立在"它们可以独立"的历史前提上。
这个前提已经被共享库彻底摧毁。
3️⃣ 硬盘早就便宜到不需要精打细算
当年分目录是为了:
节省 1.5MB 磁盘空间
今天你手机缓存都比这大几万倍。
磁盘容量、分区、挂载策略,都不再是问题。
于是就出现了今天的奇观
我们仍然在用一套:
为 PDP-11 和 1.5MB 硬盘设计的目录结构
然后后人不断给它强行补充新的解释:
/ 系统核心
/usr 发行版内容
/usr/local 本地安装
/opt 第三方软件
再加上各发行版对:
/tmp、/var/tmp、/usr/tmp
规则还互相不一致。
你以为这是"Unix 的精妙哲学"。
实际上是:
在给 50 年前的一个硬盘容量问题打补丁。
Rob Landley 的真实感受
Rob 的困惑非常真实:
我只是想知道,为什么 kill 在 /bin,killall 在 /usr/bin?
答案是:
因为历史。
不是因为逻辑。
现代 Linux 其实已经在"悄悄修正"这件事
很多新发行版已经开始做一件事:
/bin → /usr/bin 的符号链接
/sbin → /usr/sbin 的符号链接
/lib → /usr/lib 的符号链接
也就是著名的:
/usr merge
本质上就是承认:
当年这套分离,已经没有技术意义了。
结论:你每天都在为 1970 年代买单
Linux 目录结构并不是一套完美设计的产物。
它是:
PDP-11 → 磁盘不够 → 挂第二块盘 → 静态链接 → 共享库 → 现代硬件
一层一层叠出来的历史化石。
所以当你再看到:
/bin
/usr/bin
你看到的不是"精妙设计"。
你看到的是:
一块 1.5MB 的硬盘,仍然活在你的电脑里。