跳转至

第 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[主题表现]
例子 适合控制什么
环境变量 ZSHZSH_CUSTOMZSH_CACHE_DIR 路径和跨脚本状态
普通 shell 变量 ZSH_THEMEpluginsDISABLE_LS_COLORS 启动脚本的开关和选择
zstyle :omz:update:omz:lib:...:omz:plugins:... 模块化策略和细粒度覆盖
文件覆盖 custom/plugins/git/git.plugin.zsh 替换或扩展实现

3.2 ZSH:所有相对路径的根

若用户没有设置 ZSHoh-my-zsh.sh 用当前脚本路径推导它。这使得以下两种安装都可工作:

export ZSH="$HOME/.oh-my-zsh"
source "$ZSH/oh-my-zsh.sh"

或:

source /opt/tools/ohmyzsh/oh-my-zsh.sh

第二种方式依赖脚本自身的路径推导,适合临时验证或系统级安装;生产配置仍建议显式写出 ZSH,因为之后的 tools/check_for_upgrade.shZSH_COMPDUMP 和主题查找都会以它为根。

3.3 ZSH_CUSTOM:不是追加目录,而是覆盖层

很多人把 custom/ 理解成“额外配置目录”,但源码给它的优先级更高:

先查 $ZSH_CUSTOM/$filepath
否则查 $ZSH/$filepath

所以,下面这个文件会替换内置 git 插件的主动入口:

$ZSH_CUSTOM/plugins/git/git.plugin.zsh

而下面这个文件会在所有内置模块之后执行:

$ZSH_CUSTOM/aliases.zsh

二者语义不同:前者是同名替换,后者是末尾追加/覆盖。命名时要刻意选择,避免以为自己“扩展”了插件,实际却把插件完全替换掉。

3.4 ZSH_THEME 的三级查找

主题查找优先级为:

  1. $ZSH_CUSTOM/$ZSH_THEME.zsh-theme
  2. $ZSH_CUSTOM/themes/$ZSH_THEME.zsh-theme
  3. $ZSH/themes/$ZSH_THEME.zsh-theme

这允许最轻量的自定义:把一个主题文件直接放进 custom/。如果主题是可复用的集合,则放进 custom/themes/ 更清晰。

ZSH_THEME="random" 是模板支持的特殊约定:它会在主题目录中随机挑选,或使用 ZSH_THEME_RANDOM_CANDIDATES 限定候选。随机主题会降低问题复现能力,因此排查 prompt 问题时应先换成固定主题。

3.5 插件数组是空白分隔,不是逗号分隔

zsh 数组写法是:

plugins=(git docker kubectl)

换行也可以,但逗号会成为元素的一部分:

# 错误示例:可能寻找名为 git, 的插件
plugins=(git, docker,)

源码不会对名字做复杂清洗,只会通过文件存在性检查;因此一个拼写错误只在启动时打印 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:

zstyle ':omz:plugins:*' aliases no
zstyle ':omz:plugins:git' aliases yes

这是一种很有 zsh 味道的配置方式:不要求每个插件暴露自己的全局变量,而是用层级字符串统一承载模块策略。

3.7 别名禁用的真实实现

_omz_source 在 source 前保存 aliasesgaliases 两个 associative array;source 后重新赋回旧表,或对当前新增 alias 执行 unalias

这个实现有三个边界:

  • 它能处理 alias,不能识别“用 function 模拟 alias”的命令;
  • 它只保护当前 source 文件产生的副作用,不能撤销文件对全局变量的修改;
  • 禁用设置必须在 oh-my-zsh.sh source 前出现,否则文件已经执行完。

因此 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 -icompinit -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 和覆盖四步。