个人 Zsh 配置

适用场景:想要一套启动快、输入无延迟、补全体验现代的高性能 zsh 环境。你会学到 zinit 的 ice 延迟加载写法、插件选型对比(zsh-bench 实测),以及完整的 .zshrc / .zsh_aliases 参考配置。

由于系统、环境等差异可能过大,这里只是记录个人的 zsh 配置,仅供参考。

.zshrc

# My zsh settings with zinit

# ------------------- 核心配置 -------------------
# 性能优化选项
skip_global_compinit=1
DISABLE_MAGIC_FUNCTIONS=true
ZSH_DISABLE_COMPFIX=true

# 补全系统设置
COMPLETION_WAITING_DOTS="true"
ZSH_AUTOSUGGEST_MANUAL_REBIND=1
ZSH_AUTOSUGGEST_USE_ASYNC=1
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20

# ------------------- Powerlevel10k 即时提示 -------------------
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
  source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi

# ------------------- zinit 插件管理器 -------------------
source "/usr/share/zinit/zinit.zsh"
autoload -Uz _zinit
(( ${+_comps} )) && _comps[zinit]=_zinit

# zinit annexes
zinit ice wait"1" lucid as"null" for \
    zdharma-continuum/zinit-annex-as-monitor \
    zdharma-continuum/zinit-annex-bin-gem-node \
    zdharma-continuum/zinit-annex-patch-dl \
    zdharma-continuum/zinit-annex-rust

# ------------------- 主题 -------------------
zinit ice depth=1
zinit light romkatv/powerlevel10k

# ------------------- 核心插件 -------------------
# fzf
zinit ice from"gh-r" as"command"
zinit light junegunn/fzf

# 补全增强 & 补全初始化
zinit ice wait"0a" lucid atload"zicompinit; zicdreplay" blockf
zinit light zsh-users/zsh-completions

# fzf-tab
zinit ice wait"0b" lucid
zinit light Aloxaf/fzf-tab

# 自动建议
zinit ice wait"0c" lucid \
    atload'
        _zsh_autosuggest_start
        bindkey "\`" autosuggest-accept
    '
zinit light zsh-users/zsh-autosuggestions

# 历史命令
zinit ice wait"0d" lucid from"gh-r" as"program" \
    bpick"*x86_64-unknown-linux-gnu.tar.gz" \
    extract"" \
    mv"atuin*/atuin -> atuin" \
    atload'
        eval "$(atuin init zsh)"
        bindkey "^R" _atuin_search_widget
    '
zinit light atuinsh/atuin

# 语法高亮
zinit ice wait"0e" lucid atinit"zpcompinit;zpcdreplay"
zinit light zdharma-continuum/fast-syntax-highlighting

# ------------------- CLI 工具 -------------------
# 核心工具(无延迟加载)
zinit ice wait"0" lucid from"gh-r" as"program" \
    bpick"*x86_64-unknown-linux-musl.tar.gz" \
    extract"" \
    mv"eza* -> eza"
zinit light eza-community/eza

zinit ice wait"0" lucid from"gh-r" as"program" \
    bpick"*x86_64-unknown-linux-gnu.tar.gz" \
    extract"" \
    mv"bat*/bat -> bat"
zinit light sharkdp/bat

# 延迟加载工具
zinit ice wait"1" lucid from"gh-r" as"program" \
    bpick"*x86_64-unknown-linux-musl.tar.gz" \
    extract"" \
    mv"ripgrep*/rg -> rg"
zinit light BurntSushi/ripgrep

zinit ice wait"1" lucid from"gh-r" as"program" \
    bpick"*x86_64-unknown-linux-gnu.tar.gz" \
    extract"" \
    mv"fd*/fd -> fd"
zinit light sharkdp/fd

zinit ice wait"1" lucid from"gh-r" as"program" \
    bpick"*Linux_x86_64.tar.gz" \
    extract""
zinit light jesseduffield/lazydocker

zinit ice wait"1" lucid from"gh-r" as"program" \
    bpick"*linux-amd64.tar.gz" \
    extract"" \
    mv"fastfetch*/usr/bin/fastfetch -> fastfetch" \
    atclone"chmod +x fastfetch" \
    atpull"%atclone"
zinit light fastfetch-cli/fastfetch

zinit ice wait"1" lucid from"gh-r" as"program" \
    bpick"*linux_x86_64.tar.gz" \
    extract=""
zinit light muesli/duf

zinit ice wait"1" lucid as"program" pick"prettyping"
zinit load denilsonsa/prettyping

# bat-extras
zinit ice wait"1" lucid as"program" \
    pick"src/batgrep.sh" pick"src/batdiff.sh" \
    atload'alias batgrep="batgrep.sh"; alias batdiff="batdiff.sh"'
zinit light eth-p/bat-extras


# ------------------- 补全配置 -------------------
# 基础补全设置
zstyle ':completion:*' completer _expand _complete _ignored
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"
zstyle ':completion:*' menu no

# fzf-tab 基础设置
zstyle ':fzf-tab:*' use-fzf-default-opts yes

# fzf-tab 预览设置
zstyle ':fzf-tab:complete:cd:*' fzf-preview 'eza --icons -1 --color=always $realpath'
zstyle ':fzf-tab:complete:cd:*' popup-pad 30 0
zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'eza --icons -1 --color=always $realpath'
zstyle ':fzf-tab:complete:z:*' fzf-preview 'eza --icons -1 --color=always $realpath'

# 进程补全预览
zstyle ':fzf-tab:complete:kill:argument-rest' fzf-preview 'ps --pid=$word -o cmd --no-headers -w -w'
zstyle ':fzf-tab:complete:kill:argument-rest' fzf-flags '--preview-window=down:3:wrap'
zstyle ':fzf-tab:complete:kill:*' popup-pad 0 3

# fzf-tab 快捷键
zstyle ':fzf-tab:*' fzf-bindings '`:accept'
zstyle ':fzf-tab:*' switch-group '<' '>'

# ------------------- 自动建议配置 -------------------
ZSH_AUTOSUGGEST_STRATEGY=(history completion)
ZSH_AUTOSUGGEST_COMPLETION_IGNORE='( |man |pikaur -S )*'
ZSH_AUTOSUGGEST_HISTORY_IGNORE='?(#c50,)'

# ------------------- fzf 配置 -------------------
export FZF_DEFAULT_OPTS="
--ansi
--layout=reverse
--info=inline
--height=50%
--multi
--cycle
--preview-window=right:50%
--preview-window=cycle
--prompt='λ -> '
--pointer='▷'
--marker='✓'
--color=bg+:236,gutter:-1,fg:-1,bg:-1,hl:-1,hl+:-1,prompt:-1,pointer:105,marker:-1,spinner:-1
"
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'

# ------------------- Conda 配置 -------------------
export CONDA_AUTO_ACTIVATE_BASE=false
conda() {
    unfunction conda
    eval "$(/opt/miniforge/bin/conda shell.zsh hook)"
    conda $@
}
[[ "${CONDA_AUTO_ACTIVATE_BASE:-true}" == "true" ]] && {
    eval "$(/opt/miniforge/bin/conda shell.zsh hook)"
    conda activate base
}

# ------------------- 其他工具配置 -------------------
# zoxide
eval "$(zoxide init zsh --cmd cd)"

# 加载自定义别名
source $HOME/.zsh_aliases

# Powerlevel10k 配置
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh

.zsh_aliases

alias l="eza --icons --long --header"
alias ls="eza --icons --grid"
alias ll="eza --icons --long --header"
alias la="eza --icons --long --header --all"
alias lg="eza --icons --long --header --all --git"
alias tree="eza --icons --tree -L1"
alias cat="bat"
alias man="tldr"
alias mkdir='mkdir -p'
alias df="duf -style unicode -hide-mp '/run/credentials/*'"
alias top="bpytop"
alias gedit="gnome-text-editor"
alias nvidia-smi="watch -n 3 -c nvidia-smi"
alias x="unar"
alias ff="fastfetch" # 快速显示fastfetch
function tmp() {
    cd "$(mktemp -d /tmp/temp_XXX)" #创建临时目录
}

基本信息

  • System: Arch Linux x86_64
  • Terminal: kitty
  • Shell: zsh
  • Theme: powerlevel10k
  • Plugins Manerger: zinit

原有配置痛点

  1. 如果历史命令中有中文,按 up 键,会出现历史命令错位和终止终端的问题。
  2. 有些时候,命令输入延迟很高,已经输入完一段命令,但是终端是慢慢一个字一个字跳的。
  3. 性能还是不够高。

方案对比和选择

插件管理器或插件框架

序号项目说明优势劣势
1Oh My Zsh最流行的 Zsh 框架- 300+预置插件和 150+主题 - 配置简单直观 - 社区庞大- 启动速度慢 - 插件数量增加会显著降低性能
2Zinit现代化插件管理器- Turbo 模式启动速度提升 50-80% - 支持选择性禁用/启用功能 - 完整兼容 OMZ 和 Prezto 插件- 语法相对复杂 - 不适合新手
3Zim轻量级框架- 启动速度快 - 模块化设计 - 合理的默认配置 - 完整支持 OMZ 插件- 内置功能相对较少
4Sheldon可配置的插件管理器- 配置灵活 - 支持延迟加载 - 支持多种 shell- 社区相对较小
5zsh4humans优化的 Zsh 环境- 启动速度快 - 默认配置合理 - 性能优化出色- 定制性相对较低
6Antigen传统插件管理器- 类似包管理器的使用方式 - 自动更新插件- 维护不够活跃 - 性能一般
7zgen轻量级管理器- 生成静态加载文件 - 启动相对较快- 功能相对简单 - 更新较少
8zplug全功能插件管理器- 功能丰富 - 并行安装插件- 已基本停止维护 - 性能一般

在这个里面,根据轻量化、性能好、社区维护活跃等因素,我最终选择了 Zinit 作为插件管理器。

插件

  1. 语法高亮:fast-syntax-highlighting
  2. 命令补全:zsh-completionsfzf-tab
  3. 智能建议:zsh-autosuggestions
  4. 目录跳转:zoxide
序号项目说明优势劣势
1zoxideRust 编写的现代化目录跳转工具- 性能最快,启动速度快 - 使用简单直观 - 支持所有主流 shell- 需要额外安装 - 不支持相对路径跳转
2autojumpPython 编写的经典跳转工具- 功能丰富完整 - 高级特性多- 学习曲线较陡 - 性能相对较慢
3zZsh 内置的目录跳转插件- 无需额外安装 - 与 Zsh 深度集成- 功能相对基础 - 仅支持 Zsh
4z.luaLua 实现的跳转工具- 跨平台支持好 - 配置灵活- 性能比 zoxide 慢 - 需要 Lua 环境
5zsh-zZsh 专用的 z 实现- 轻量级 - 安装简单- 仅支持 Zsh - 功能较少
6ZLOcationShell 原生实现的跳转工具- 无外部依赖 - 性能稳定- 功能相对简单 - 社区较小
  1. 历史命令:atuin
序号项目说明优势劣势
1atuin基于 SQLite 的现代化 shell 历史记录工具- 支持多设备同步 - 支持端到端加密 - 可按目录/主机等过滤搜索 - 记录命令执行时间和退出码 - 支持自托管同步服务器 - 配置简单,安装便捷- 首次打开仪表板较慢 - 在 mosh 下可能出现屏幕显示问题 - 同步机制不够直观 - 配置无法跨设备同步
2zsh-histdb基于 SQLite 的 Zsh 历史记录插件- 记录命令工作目录 - 记录命令执行主机 - 支持多数据库合并 - 与 zsh-autosuggestions 集成良好 - 支持按目录搜索历史- 不使用传统文本文件存储 - 项目维护不够活跃 - 仅支持 Zsh - 配置相对复杂
  1. 主题美化:powerlevel10k

第三方命令行工具管理

由于该配置会同步 Docker深度学习环境远程服务器使用,系统包管理器不同(有 ubuntuarchlinuxdebian 等),故第三方命令行工具使用 zinit 管理,而非使用包管理器管理。则新建一系统时安装 zshzinit,再同步配置即可,其余的交给 zinit 管理。

TODO: 之后用 chezimo 管理配置文件并同步到各个系统。

测试工具

这里使用 zsh-bench 基准工具来测试 zsh 交互性能,再进行对比。

测量指标

  1. first_prompt_lag_ms (首次提示符延迟):打开新终端时,显示第一个命令提示符所需的时间
    • 良好: < 50ms
    • 较差: > 100ms
  2. first_command_lag_ms (首次命令延迟):输入第一个命令到执行完成的时间
    • 良好: < 200ms
    • 较差: > 500ms
  3. command_lag_ms (命令延迟):执行后续命令的平均响应时间
    • 良好: < 10ms
    • 较差: > 50ms
  4. input_lag_ms (输入延迟):按键到字符显示在屏幕上的时间
    • 良好: < 30ms
    • 较差: > 50ms
  5. exit_time_ms (退出时间):输入 exit 或按 Ctrl+D 到终端完全关闭的时间
    • 良好: < 100ms
    • 较差: > 200ms

测试命令如下:

./zsh-bench -i 30 -l yes -g yes

测试结果

==> benchmarking login shell of user xiadengma ...
creates_tty=0
has_compsys=0
has_syntax_highlighting=0
has_autosuggestions=0
has_git_prompt=1
first_prompt_lag_ms=18.829
first_command_lag_ms=78.340
command_lag_ms=4.930
input_lag_ms=3.903
exit_time_ms=45.429

可以看到当前 zsh 配置在性能上表现良好,响应速度快。

验证与自查

  1. 新开终端 first_prompt_lag_ms 应 < 50ms(用 ./zsh-bench -i 30 -l yes -g yes 复测)
  2. 输入历史命令中的中文后按 up 键,不再错位或卡死终端
  3. 快速输入一段命令,字符不再逐个蹦出(input_lag_ms 无感)
  4. Ctrl+R 打开 atuin 历史搜索,cd 命令走 zoxide 跳转正常

参考