第 3 章:配置与优先级 —— 变量、zstyle 和目录覆盖¶
Oh My Zsh 的配置不是一个单独的配置文件,而是三种机制叠加:环境变量、zsh option/style、文件系统覆盖。
3.1 配置分层¶
flowchart TB
A[命令行环境变量] --> D[oh-my-zsh.sh]
B[~/.zshrc 中的变量] --> D
C[~/.zshrc 中的 zstyle] --> D
D --> E[lib 默认行为]
E --> F[插件行为]
F --> G[custom 覆盖]
G --> H[主题表现]
| 层 | 例子 | 适合控制什么 |
|---|---|---|
| 环境变量 | ZSH、ZSH_CUSTOM、ZSH_CACHE_DIR |
路径和跨脚本状态 |
| 普通 shell 变量 | ZSH_THEME、plugins、DISABLE_LS_COLORS |
启动脚本的开关和选择 |
zstyle |
:omz:update、:omz:lib:...、:omz:plugins:... |
模块化策略和细粒度覆盖 |
| 文件覆盖 | custom/plugins/git/git.plugin.zsh |
替换或扩展实现 |
3.2 ZSH:所有相对路径的根¶
若用户没有设置 ZSH,oh-my-zsh.sh 用当前脚本路径推导它。这使得以下两种安装都可工作:
或:
第二种方式依赖脚本自身的路径推导,适合临时验证或系统级安装;生产配置仍建议显式写出 ZSH,因为之后的 tools/check_for_upgrade.sh、ZSH_COMPDUMP 和主题查找都会以它为根。
3.3 ZSH_CUSTOM:不是追加目录,而是覆盖层¶
很多人把 custom/ 理解成“额外配置目录”,但源码给它的优先级更高:
所以,下面这个文件会替换内置 git 插件的主动入口:
而下面这个文件会在所有内置模块之后执行:
二者语义不同:前者是同名替换,后者是末尾追加/覆盖。命名时要刻意选择,避免以为自己“扩展”了插件,实际却把插件完全替换掉。
3.4 ZSH_THEME 的三级查找¶
主题查找优先级为:
$ZSH_CUSTOM/$ZSH_THEME.zsh-theme$ZSH_CUSTOM/themes/$ZSH_THEME.zsh-theme$ZSH/themes/$ZSH_THEME.zsh-theme
这允许最轻量的自定义:把一个主题文件直接放进 custom/。如果主题是可复用的集合,则放进 custom/themes/ 更清晰。
ZSH_THEME="random" 是模板支持的特殊约定:它会在主题目录中随机挑选,或使用 ZSH_THEME_RANDOM_CANDIDATES 限定候选。随机主题会降低问题复现能力,因此排查 prompt 问题时应先换成固定主题。
3.5 插件数组是空白分隔,不是逗号分隔¶
zsh 数组写法是:
换行也可以,但逗号会成为元素的一部分:
源码不会对名字做复杂清洗,只会通过文件存在性检查;因此一个拼写错误只在启动时打印 plugin not found,不会阻止其他插件加载。
3.6 zstyle 的层级匹配¶
Oh My Zsh 用 context 把配置分层。例如别名控制:
# 所有 lib 和 plugin 都禁用 alias
zstyle ':omz:*' aliases no
# 只禁用 lib
zstyle ':omz:lib:*' aliases no
# 只禁用 git plugin
zstyle ':omz:plugins:git' aliases no
更具体的 context 会覆盖更宽的 context:
这是一种很有 zsh 味道的配置方式:不要求每个插件暴露自己的全局变量,而是用层级字符串统一承载模块策略。
3.7 别名禁用的真实实现¶
_omz_source 在 source 前保存 aliases 和 galiases 两个 associative array;source 后重新赋回旧表,或对当前新增 alias 执行 unalias。
这个实现有三个边界:
- 它能处理 alias,不能识别“用 function 模拟 alias”的命令;
- 它只保护当前 source 文件产生的副作用,不能撤销文件对全局变量的修改;
- 禁用设置必须在
oh-my-zsh.shsource 前出现,否则文件已经执行完。
因此 zstyle 不是沙箱,只是针对 alias 的回滚策略。
3.8 常用开关的生命周期¶
| 设置 | 读取位置 | 影响 |
|---|---|---|
DISABLE_MAGIC_FUNCTIONS |
lib/misc.zsh |
是否注册 URL/括号粘贴 magic |
DISABLE_LS_COLORS |
lib/theme-and-appearance.zsh |
是否设置 LS_COLORS/LSCOLORS |
DISABLE_AUTO_TITLE |
lib/termsupport.zsh |
是否注册终端标题 hook |
CASE_SENSITIVE |
lib/completion.zsh |
补全 matcher,随后被 unset |
HYPHEN_INSENSITIVE |
lib/completion.zsh |
_ 和 - 的匹配策略,随后被 unset |
ZSH_DISABLE_COMPFIX |
oh-my-zsh.sh |
compinit -i 或 compinit -u |
DISABLE_UNTRACKED_FILES_DIRTY |
lib/git.zsh |
Git prompt 是否忽略 untracked |
GIT_STATUS_IGNORE_SUBMODULES |
lib/git.zsh |
dirty 检查的 submodule 策略 |
有些变量被读取后 unset,这是一种防止后续脚本误用的做法;配置应放在 source 前,而不是期待它一直存在。
3.9 推荐的配置结构¶
~/.zshrc
├── 路径和启动前 zstyle
├── ZSH_THEME / plugins
├── source "$ZSH/oh-my-zsh.sh"
└── 用户临时覆盖(必要时)
$ZSH_CUSTOM/
├── aliases.zsh
├── environment.zsh
├── functions.zsh
├── plugins/<name>/<name>.plugin.zsh
└── themes/<name>.zsh-theme
如果一个设置影响初始化顺序、别名隔离、补全或更新检查,就放在 source 前;如果只是用户最终 alias 或函数,就放在 custom 文件中而不是不断膨胀 .zshrc。
下一章将把“插件名如何变成运行时代码”拆成发现、fpath、source 和覆盖四步。