Files
hugo-blog/content/posts/my-zsh-terminal-setup.md
2026-05-28 22:20:00 +08:00

14 KiB
Raw Blame History

date, draft, title, tags, categories
date draft title tags categories
2026-05-28T22:05:00+08:00 false 我的 Zsh 终端配置Zinit、Powerlevel10k 与日常效率优化
zsh
terminal
dotfiles
zinit
powerlevel10k
技术

前言

一个好用的 Shell 配置,不应该只是“看起来很酷”。它更应该做到三件事:

  1. 启动快:进入终端后立刻可输入命令,而不是等待一堆插件初始化。
  2. 提示准当前目录、Git 状态、命令执行结果、语言环境等信息一眼可见。
  3. 操作顺手:常用命令短、路径跳转快、补全和历史建议足够智能。

这篇文章记录我的 Zsh 配置思路。整体方案是:Zinit 管理插件Powerlevel10k 负责提示符Oh My Zsh 提供成熟插件生态,再配合 eza、yazi、pnpm、n 等工具优化日常开发体验

整体结构

我的 Zsh 配置主要由两个文件组成:

~/.zshrc       # 主配置环境变量、zinit、插件、别名、函数
~/.p10k.zsh    # Powerlevel10k 主题配置

加载顺序大致如下:

启动 Zsh
  |
  v
Powerlevel10k instant prompt
  |
  v
基础环境变量与 Shell options
  |
  v
加载 zinit
  |
  v
加载 OMZ library / Powerlevel10k / 插件
  |
  v
source ~/.p10k.zsh
  |
  v
注册 alias / function / PATH

这种拆分的好处是:.zshrc 保持“启动流程与插件管理”,.p10k.zsh 专注“提示符长什么样”。以后更换主题时,也不会影响插件和别名体系。

用 instant prompt 提升启动体验

配置最顶部是 Powerlevel10k 的 instant prompt

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

它的作用是:在完整配置加载完成之前,先显示一个临时 Prompt让终端看起来“秒开”。

同时我设置了:

typeset -g POWERLEVEL9K_INSTANT_PROMPT=quiet

这样可以减少 instant prompt 对启动时输出内容的干扰。对于需要频繁打开新终端、tmux pane 或远程会话的人来说,这一点体验提升很明显。

基础环境与 Zsh options

path=(~/.local/bin $path)
typeset -x XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"

setopt correct
setopt interactive_comments

这里做了几个基础设定:

配置 作用
~/.local/bin 前置到 PATH 优先使用用户级安装的命令
XDG_CONFIG_HOME 统一配置目录,默认指向 ~/.config
setopt correct 命令输错时给出纠正建议
setopt interactive_comments 交互式 Shell 中也允许使用 # 注释

interactive_comments 很适合在终端里临时记录命令意图,比如粘贴多行命令时可以保留注释说明。

为什么选择 Zinit

插件管理器我使用的是 Zinit

ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git"
[[ ! -d "${ZINIT_HOME}" ]] && mkdir -p "$(dirname "${ZINIT_HOME}")"
[[ ! -d "${ZINIT_HOME}/.git" ]] && git clone https://gh-proxy.org/https://github.com/zdharma-continuum/zinit.git "${ZINIT_HOME}"
source "${ZINIT_HOME}/zinit.zsh"

Zinit 的核心价值是:可以精细控制插件加载时机。比如有些插件必须同步加载,有些插件可以延迟 1 秒、2 秒、3 秒再加载;对于启动速度敏感的 Shell 配置来说,这比简单地 source 一堆脚本更可控。

配置里还使用了 GitHub 代理地址,主要是为了在国内网络环境下更稳定地安装 Zinit。你也可以按自己的网络情况替换为官方仓库地址。

先加载 Oh My Zsh 的基础库

我没有直接使用完整的 Oh My Zsh 框架,而是通过 Zinit 按需加载其中的 library 和 plugin。

同步加载的 OMZ library

for i in theme-and-appearance.zsh git.zsh prompt_info_functions.zsh history.zsh; do
  zinit snippet "OMZL::${i}"
done

延迟加载的 OMZ library

for i in completion.zsh key-bindings.zsh; do
  zinit ice lucid wait="1"
  zinit snippet "OMZL::${i}"
done

这里的思路是:

类型 加载策略 原因
theme / git / prompt / history 同步加载 主题和提示符依赖,越早越好
completion / key-bindings 延迟加载 对首屏 Prompt 不是硬依赖

补全初始化则交给:

zpcompinit
zpcdreplay

这样可以配合 Zinit 的补全 replay 机制,让插件延迟加载后仍然能正确注册补全。

Powerlevel10k两行式 Prompt

主题使用 Powerlevel10k

zinit ice depth=1
zinit light romkatv/powerlevel10k

[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh

depth=1 可以减少 clone 体积,只拉取必要历史。

我的 .p10k.zsh 是通过 p10k configure 生成的 rainbow 风格配置,主要特点是:

项目 配置
字体 Nerd Font v3
风格 powerline + rainbow
Prompt 两行式
分隔符 angled separators
图标 small icons / many icons
显示密度 sparse、concise

左侧 Prompt 保留最核心的信息:

POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(
  os_icon
  dir
  vcs
  newline
  prompt_char
)

右侧 Prompt 则放一些上下文信息例如命令状态、执行耗时、后台任务、Python 虚拟环境、Node 环境、Kubernetes context、Terraform workspace、云 CLI profile、时间等。

这种布局的优点是:左边只显示当前操作最常用的信息,右边显示“有就看、没有也不影响”的上下文。两行式 Prompt 也能避免路径太长时挤压命令输入区域。

插件设计:按“必要程度”延迟加载

我的插件并不是一股脑同步加载,而是按使用频率和必要程度分层。

插件 加载方式 用途
command-not-found wait=0 命令不存在时提示可安装的软件包
colored-man-pages wait=3 彩色 man 页面
fast-syntax-highlighting async 命令行语法高亮
zsh-autosuggestions async + atload 基于历史记录的命令建议
sudo wait=2 双击 Esc 给当前命令加 sudo
z wait=1 根据访问频率跳转目录
git wait=1 Git 常用别名与函数
extract wait=1 一条命令解压多种格式
kubectl wait=1 Kubernetes 别名、补全与辅助函数

其中最影响交互体验的是两个插件:

zinit light zdharma-continuum/fast-syntax-highlighting
zinit light zsh-users/zsh-autosuggestions
  • fast-syntax-highlighting:输入命令时实时高亮,能提前发现命令、路径、参数是否写错。
  • zsh-autosuggestions:根据历史记录给出灰色建议,按右方向键即可补全。

这两个插件会让命令行从“纯文本输入框”变成“带反馈的交互环境”。

文件列表eza 优先ls 兜底

我把常用 ls 系列命令封装成了别名,如果系统安装了 eza,就优先使用 eza

if [[ -n "$(command -v eza)" ]]; then
  DISABLE_LS_COLORS=true
  alias ls='eza --color=auto'
  alias l='eza -lbah --icons=auto'
  alias la='eza -labgh --icons=auto'
  alias ll='eza -lbg --icons=auto'
  alias lt='eza -lTbg --icons=auto'
  alias lsa='eza -lbagR --icons=auto'
  alias lst='eza -lTabgh --icons=auto'
else
  alias ls='ls --color=auto'
  alias l='ls -lah'
  alias la='ls -lAh'
  alias ll='ls -lh'
  alias lsa='ls -lah'
  alias lst='tree -pCsh'
fi

常用别名含义如下:

别名 作用
l 长列表,显示隐藏文件、人类可读大小、图标
la 类似 l,但更适合查看权限和分组信息
ll 简洁长列表
lt 树状展示目录
lsa 递归列出所有文件
lst 树状递归展示并包含隐藏文件

这里的关键是“有增强工具就增强,没有就优雅降级”。配置可以在新机器上直接使用,不会因为缺少 eza 导致 Shell 启动失败。

路径跳转与目录历史

alias ...=../..
alias ....=../../..
alias .....=../../../..
alias ......=../../../../..

alias 1='cd -'
alias 2='cd -2'
alias 3='cd -3'
# ...一直到 9

这组别名解决两个常见问题:

  1. 多级返回目录时不用反复输入 cd ../../..
  2. 在多个目录之间来回切换时,可以直接用 19 访问目录栈。

配合 OMZ 的 z 插件,可以覆盖两类跳转场景:

  • 已知相对路径:使用 .......
  • 经常访问的目录:使用 z <keyword>

yazi退出文件管理器后自动 cd

配置中有一个很实用的 y() 函数:

function y() {
  local tmp cwd
  tmp="$(mktemp -t yazi-cwd.XXXXXX)"
  yazi "$@" --cwd-file="$tmp"
  cwd="$(cat -- "$tmp")"
  if [[ -n "$cwd" && "$cwd" != "$PWD" ]]; then
    builtin cd -- "$cwd"
  fi
  rm -f -- "$tmp"
}

普通文件管理器的问题是:你在里面进入了某个目录,但退出后 Shell 仍然停留在原目录。这个函数通过 --cwd-file 记录 yazi 退出时所在目录,然后让当前 Shell 自动 cd 过去。

实际体验就是:

y
# 在 yazi 中进入目标目录
# 退出 yazi 后Shell 自动切换到那个目录

这比在终端里反复 cdls、再 cd 要顺手很多。

Git、解压、sudo 与搜索

除了视觉和补全,我还保留了一些非常实用的小别名:

alias _='sudo '
alias gc1='git clone --recursive --depth=1'
alias md='mkdir -p'
alias rd='rmdir'
alias afind='ack -il'
alias grep='grep --color=auto'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
别名 用途
_ 快速给命令加 sudo 前缀
gc1 浅克隆并递归拉取子模块
md 创建多级目录
rd 删除空目录
afind ack 搜索包含关键词的文件
grep 系列 默认开启彩色输出

此外 OMZ 的 extract 插件也很省心:不需要记住 tar.gzzipxzbz2 等格式分别怎么解压,统一用 extract 即可。

代理开关:为国内网络环境准备

alias proxy-on='export http_proxy=http://127.0.0.1:7890 https_proxy=http://127.0.0.1:7890'
alias proxy-off='unset http_proxy https_proxy'

这两个别名适合临时让命令行工具走本地代理,例如拉取 GitHub 仓库、安装依赖、访问国外 API 等。

proxy-on
# 执行需要代理的命令
proxy-off

我没有把代理永久写进环境变量,因为那样容易影响内网服务、容器网络和一些只需要直连的命令。按需开启更可控。

Node 与前端工具链

配置末尾还包含 pnpm 和 n 的环境变量:

export PNPM_HOME="/root/.local/share/pnpm"
case ":$PATH:" in
  *":$PNPM_HOME/bin:"*) ;;
  *) export PATH="$PNPM_HOME/bin:$PATH" ;;
esac

export N_PREFIX="$HOME/n"
[[ :$PATH: == *":$N_PREFIX/bin:"* ]] || PATH+=":$N_PREFIX/bin"

这里有两个目的:

  1. pnpm 的全局 bin 目录加入 PATH,方便直接运行全局安装的 CLI。
  2. n 管理的 Node.js 路径加入 PATH,让当前 Shell 使用用户目录下的 Node 版本。

如果你也用 pnpm 和 n建议把它们放在 Shell 配置末尾,避免覆盖前面插件初始化所需的环境。

依赖清单

这套配置推荐安装的依赖如下:

依赖 必需 用途
zsh Shell 本体
git 安装 zinit、拉取插件
zinit 插件管理器
powerlevel10k Prompt 主题
Nerd Font 正确显示图标和 powerline 符号
eza 可选 更现代的 ls 替代品
tree 可选 eza 不存在时作为树状列表兜底
ack 可选 afind 搜索别名
yazi 可选 终端文件管理器
kubectl 可选 Kubernetes 补全与别名
command-not-found 可选 命令不存在时提示安装包
pnpm 可选 Node 包管理器
n 可选 Node 版本管理

最小安装只需要:zshgit、Nerd Font。其他工具可以按需补齐。

可复用的安装步骤

如果要在新机器上复用这套配置,可以按这个流程:

# 1. 安装基础依赖
sudo apt update
sudo apt install -y zsh git

# 2. 可选增强工具
sudo apt install -y tree ack

# 3. 安装 eza / yazi / pnpm / n 等工具
# 不同发行版包名可能不同,可按实际系统调整

# 4. 放置配置文件
cp .zshrc ~/.zshrc
cp .p10k.zsh ~/.p10k.zsh

# 5. 切换默认 Shell
chsh -s "$(command -v zsh)"

首次进入 Zsh 时,配置会自动安装 Zinit并通过 Zinit 拉取 Powerlevel10k 和插件。

我的取舍

这套配置没有追求“插件越多越好”,而是围绕日常使用做了几个取舍:

  1. 不完整引入 Oh My Zsh:只按需加载 OMZ library 和 plugin减少框架开销。
  2. Prompt 信息分层:左侧保留目录与 Git右侧显示环境上下文。
  3. 增强工具必须有 fallbackeza 不存在就退回 ls,避免新机器启动失败。
  4. 代理手动开关:避免代理污染所有命令。
  5. 插件延迟加载:把首屏可交互时间放在第一优先级。

总结

我的 Zsh 配置可以概括为:

  • Zinit:负责插件安装、延迟加载和补全 replay。
  • Powerlevel10k:提供高信息密度、低干扰的两行 Prompt。
  • OMZ snippets:按需复用 Oh My Zsh 的成熟插件生态。
  • eza / yazi / z / autosuggestions:提升文件浏览、目录跳转和命令输入效率。
  • pnpm / n:补齐前端和 Node.js 开发环境。

终端配置是一个长期迭代的系统。最好的配置不是最复杂的配置,而是能让你在每天打开终端时少想一步、少敲几个字、少等几百毫秒的配置。