系统目录规范

已修订更新于

首发于

系统目录规范

你可能听过 XDG、FHS 这两个概念。我最初接触 FHS,是在《鸟哥的 Linux 私房菜》里。

  1. 我最开始学 Linux 就很疑惑:为什么 Linux 的目录树会是现在这样。
  2. 后来接触 Red Hat 系的 Fedora,在官方文档里又撞上 XDG。顺着线索往下搜,发现它是一套面向桌面与用户级应用的目录约定;再回头看,就自然联想到 FHS 内容。

先把名字摆正:

一层直觉:厂商默认 → /etc 覆盖 → 用户目录再覆盖

Linux 目录规范里,其实已经内嵌了一套「默认加载 / 覆盖」的顺序。日常改软件行为时,大致是这样分层的:

  1. 厂商默认资源在 /usr
    包管理器装进来的只读默认配置、桌面文件、图标、schema 等,通常落在 /usr/share、/usr/lib 一类路径。它们是发行版/软件包自带的回退值,正常不该手改——下次升级会被盖掉。

  2. 要改行为,优先在 /etc 覆盖
    主机级、管理员可控的配置放在 /etc(以及软件自己的 /etc/某软件/)。系统启动或守护进程读配置时,常见模式是:先读 /usr 里的默认,再被 /etc 盖住。

  3. 若还能跑在用户级,再落到家目录
    同一软件若支持 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)。于是大致有了:

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/ 额外数据搜索路径,: 分隔,越靠前越优先

完整查找时:

同一信息出现在多处时,更靠前 / 更「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 是另一份规范,常一起被发行版启用。)

小结

理解这三层之后,再看某个软件「配置到底改哪」,通常就不会再在 /usr、/etc 和 ~ 之间瞎撞了。

评论

可对整篇留言,或划选正文中的句子后评论该段。

登录后即可发表评论。

  • 还没有公开评论。
↑