系统目录规范
你可能听过 XDG、FHS 这两个概念。我最初接触 FHS,是在《鸟哥的 Linux 私房菜》里。
- 我最开始学 Linux 就很疑惑:为什么 Linux 的目录树会是现在这样。
- 后来接触 Red Hat 系的 Fedora,在官方文档里又撞上 XDG。顺着线索往下搜,发现它是一套面向桌面与用户级应用的目录约定;再回头看,就自然联想到 FHS 内容。
先把名字摆正:
- FHS: Filesystem Hierarchy Standard:从「整台机器怎么摆文件」出发的文件系统逻辑结构标准。书里有时会写成 HFS,其实指的就是 FHS。
- XDG Base Directory Specification:XDG 原指 X Desktop Group(后来演变成 freedesktop.org),这套规范专门约定用户级配置、数据、缓存等该放哪、按什么顺序找。
一层直觉:厂商默认 → /etc 覆盖 → 用户目录再覆盖
Linux 目录规范里,其实已经内嵌了一套「默认加载 / 覆盖」的顺序。日常改软件行为时,大致是这样分层的:
-
厂商默认资源在
/usr
包管理器装进来的只读默认配置、桌面文件、图标、schema 等,通常落在/usr/share、/usr/lib一类路径。它们是发行版/软件包自带的回退值,正常不该手改——下次升级会被盖掉。 -
要改行为,优先在
/etc覆盖
主机级、管理员可控的配置放在/etc(以及软件自己的/etc/某软件/)。系统启动或守护进程读配置时,常见模式是:先读/usr里的默认,再被/etc盖住。 -
若还能跑在用户级,再落到家目录
同一软件若支持 per-user 配置,还会在用户目录下再开一层——传统是~/.某软件,更现代的是 XDG 约定的~/.config、~/.local/share等。用户层优先于系统层。
可以粗记成:
/usr/...(厂商默认,回退)
↑ 被覆盖
/etc/...(本机管理员配置)
↑ 被覆盖
~/.config / ~/.local/...(当前用户配置)
FHS 管的是前半段「整机怎么分目录」;XDG 把后半段「用户家目录别再一团乱」说清楚了。
目录树从哪来:一点历史渊源
现在看到的 /bin、/etc、/usr、/var、/home,并不是某次委员会一次性设计出来的,而是从早期 Unix 一点点长出来,再被标准文档「追认」成习惯法。
从 Multics 到 Unix 的目录树
Unix 的树状目录思路,很大程度继承自 Multics:文件挂在目录下,目录再挂目录,最终汇到一个根。早期 PDP-7 / PDP-11 上的 Unix 资源极紧——根盘很小,程序和用户数据很快就把第一块盘挤爆。于是出现了很实用的权宜之计:再挂一块盘,上面继续放「用户侧」的东西。那块盘的挂载点,就叫 /usr。
/usr 名字的反转
最早 /usr 字面意思就是 user:用户家目录曾经真的放在这里。后来系统程序也装不下了,于是在 /usr 下又长出 /usr/bin、/usr/lib、/usr/tmp……久而久之,用户家目录迁到了 /home,/usr 反而变成「可共享、宜只读的第二层次系统树」——名字还是 usr,含义已经翻了个面。这也是很多人第一次看 man hier 或 FHS 时最容易懵的一点。
/etc:本来就是「等等」
/etc 早期就是 et cetera:塞不下别处的杂项。后来范围收窄,FHS 把它基本限定为「本机静态配置」,不该再塞可执行文件。民间也有人把 etc 回写成 Editable Text Configuration,那是后起的助记,不是原始词源。
/var:把「会变的」拆出去
随着机器常驻运行,日志、锁、队列、缓存、运行时状态越来越多。把这些可变数据从 /usr 这种宜只读的树里拆出去,就形成了 /var(variable)。于是大致有了:
- 根文件系统:能单用户启动、修系统的最小集合
/usr:大体只读、可跨机共享的程序与只读资源/var:本机会增长、会改写的数据/etc:本机配置/home:真人用户的家
FSSTND → FHS:把习惯写成标准
Linux 普及后,各发行版目录略有出入,装软件和写文档都痛苦。1993 年起有人整理 Linux 目录约定,1994 年推出 FSSTND(Filesystem Standard);1995 年前后目标扩大到更一般的 Unix-like,改名 FHS(Filesystem Hierarchy Standard)。现行常见引用是 FHS 3.0(2015)。它描述的是「该长什么样」,具体发行版仍可能有小差异,但主干已经高度同构。
所以:目录树先是工程妥协与历史惯性,FHS 是事后对齐的说明书;XDG 则是在桌面与用户应用爆炸之后,专门收拾「家目录污染」的下一层约定。
FHS 里几个常打交道的目录(极简)
| 路径 | 大致角色 |
|---|---|
/ |
根;启动与急救所需的最小树 |
/bin、/sbin |
基本命令(现代发行版常与 /usr/bin 等合并) |
/etc |
本机配置 |
/home |
用户家目录 |
/usr |
可共享、宜只读的程序与资源(厂商默认多在这里) |
/usr/local |
本机管理员自装软件,优先级常高于 /usr |
/var |
可变数据:日志、缓存、库状态等 |
/tmp、/run |
临时文件与运行时(重启可清) |
/opt |
第三方整包软件的可选落点 |
和「覆盖顺序」对应时,记住两点就够:默认资源偏 /usr,本机覆盖偏 /etc,用户覆盖偏 $HOME。
XDG Base Directory:目录列表
XDG Base Directory Specification(当前常见为 0.8,2021-05-08)不重新发明整棵系统树,只约定:用户相关的配置 / 数据 / 状态 / 缓存 / 运行时,相对哪些「基目录」读写,以及多目录时的优先级。
所有相关环境变量里的路径都必须是绝对路径;相对路径应视为无效并忽略。
用户可写的基目录
| 环境变量 | 未设置时的默认值 | 放什么 |
|---|---|---|
$XDG_CONFIG_HOME |
$HOME/.config |
用户级配置(对标 /etc) |
$XDG_DATA_HOME |
$HOME/.local/share |
用户级数据文件(对标 /usr/share) |
$XDG_STATE_HOME |
$HOME/.local/state |
应持久但不必可移植的状态:历史、日志、窗口布局、undo 等(对标 /var/lib 一类) |
$XDG_CACHE_HOME |
$HOME/.cache |
可丢弃的缓存(对标 /var/cache) |
$XDG_RUNTIME_DIR |
由登录会话提供(常见如 /run/user/$UID) |
套接字、命名管道等运行时对象;须属主独占、权限 0700;随登录生命周期,重启/完全注销后不应残留 |
另外,规范还点名:用户级可执行文件可放在 $HOME/.local/bin。发行版宜把它放进 $PATH。若 $HOME 在异构架构机器间共享,往这里塞编译产物要小心。
只读搜索路径(带优先级)
| 环境变量 | 未设置时的默认值 | 含义 |
|---|---|---|
$XDG_CONFIG_DIRS |
/etc/xdg |
额外配置搜索路径,: 分隔,越靠前越优先 |
$XDG_DATA_DIRS |
/usr/local/share/:/usr/share/ |
额外数据搜索路径,: 分隔,越靠前越优先 |
完整查找时:
- 配置:先
$XDG_CONFIG_HOME,再依次扫$XDG_CONFIG_DIRS - 数据:先
$XDG_DATA_HOME,再依次扫$XDG_DATA_DIRS
同一信息出现在多处时,更靠前 / 更「HOME」的那份胜出。$XDG_CONFIG_HOME 永远高于 $XDG_CONFIG_DIRS;$XDG_DATA_HOME 永远高于 $XDG_DATA_DIRS。
这和文章开头的分层完全同构,只是把「用户层」从散落的 ~/.* 收成了几棵固定的树:
写配置 → $XDG_CONFIG_HOME(默认 ~/.config)
读配置 → $XDG_CONFIG_HOME → $XDG_CONFIG_DIRS(默认 /etc/xdg)
↑ 其中 /etc/xdg 之上,软件包默认数据还常在 /usr/share
写数据 → $XDG_DATA_HOME(默认 ~/.local/share)
读数据 → $XDG_DATA_HOME → $XDG_DATA_DIRS(默认 /usr/local/share:/usr/share)
写状态 → $XDG_STATE_HOME(默认 ~/.local/state)
写缓存 → $XDG_CACHE_HOME(默认 ~/.cache)
运行时 → $XDG_RUNTIME_DIR(常见 /run/user/$UID)
可执行 → ~/.local/bin
规范还约定:引用「某个配置文件」时,默认安装位置往往是 /etc/xdg/subdir/filename;「某个数据文件」默认安装在 /usr/share/subdir/filename。查找则按上面的基目录列表拼 subdir/filename。目标目录不存在、要写入时,应尝试以权限 0700 创建;已存在则不要擅自改权限。
和「传统点文件」的关系
很多老软件仍用 ~/.bashrc、~/.vimrc 这种直接落在 $HOME 的隐藏文件。XDG 并不强制全世界一夜改完,而是给新应用一条干净路径:配置进 ~/.config,数据进 ~/.local/share,状态进 ~/.local/state,缓存进 ~/.cache,别再把家目录糊成坟场。
(旁支:还有 XDG user directories,约定 Desktop、Documents、Downloads 等「用户可见文件夹」的本地化路径,和 Base Directory 是另一份规范,常一起被发行版启用。)
小结
- 历史:目录树来自早期 Unix 的磁盘妥协与 Multics 式树模型;
/usr、/etc的名字往往比现行含义更老。 - FHS:把整机分层写成标准——
/usr宜只读默认,/etc本机覆盖,/var可变数据,/home用户。 - XDG:把用户层再拆成 config / data / state / cache / runtime,并明确与
/etc/xdg、/usr/share之间的查找优先级。
理解这三层之后,再看某个软件「配置到底改哪」,通常就不会再在 /usr、/etc 和 ~ 之间瞎撞了。