跳转到主要内容
工具箱

Zsh 一键复刻配置

约 4 分钟阅读 实体

Zsh 一键复刻配置

本文用于在新 macOS 机器上一键复刻本人当前的 zsh 环境。下方第一节是给 Claude Code 的执行提示词,直接复制粘贴即可;之后是配置快照与人工说明。

适用环境:macOS (Apple Silicon),Homebrew 装在 /opt/homebrew,主目录 ~ = /Users/<you>。 快照时间:2026-05-20,基于 zsh + Oh My Zsh + Powerlevel10k。


1. 给 Claude Code 的一键复刻指令

把下面这段贴给 Claude Code:

请按 ~/Documents/_work/99_code/blogv2/src/content/docs/toolbox/tools/zsh-setup.md
里"安装清单"和"~/.zshrc 全文"两节,在本机复刻我的 zsh 环境。

约束:
- 不要覆盖已存在文件;先把 ~/.zshrc、~/.zshenv、~/.zprofile 备份成 *.bak.<today>
- 顺序:Homebrew → oh-my-zsh → powerlevel10k 主题 → 两个 zsh 插件
  → nvm/node → uv → bun → pnpm → miniforge → 写 ~/.zshrc / ~/.zshenv / ~/.zprofile
- Homebrew 必须用 USTC 镜像(见 ~/.zshrc 中的 HOMEBREW_* 变量),否则首次拉取会卡死
- 把 ~/.zshrc 替换为本文档"~/.zshrc 全文"那一节里的完整内容
- 替换完成后让我自己运行 `p10k configure` 选样式
- 全程只问我一次:是否需要把全部 brew 软件包(leaves + casks)也装回来

2. 配置组件清单

组件作用安装方式
Homebrew包管理(走 USTC 镜像)官方一键脚本
Oh My Zshzsh 框架官方一键脚本,仓库在 ~/.oh-my-zsh
Powerlevel10k主题,含 instant promptgit clone 到 ~/.oh-my-zsh/custom/themes/powerlevel10k
zsh-autosuggestions历史补全git clone 到 ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions
zsh-syntax-highlighting命令高亮git clone 到 ~/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting
nvmNode 版本管理(lazy load)官方脚本到 ~/.nvm,默认 v24 系列
Go~/go 作为 GOPATHbrew
uv替代 pip,配合 miniforge 解释器curl -LsSf https://astral.sh/uv/install.sh | sh
BunJS runtimecurl -fsSL https://bun.sh/install | bash
pnpm包管理,PNPM_HOME=~/Library/pnpmbrew
Miniforgeconda 系 Pythonbrew cask / 官方安装包;解释器路径 ~/miniforge3/bin/python
Fira Code Nerd FontP10k 图标字体brew install --cask font-fira-code-nerd-font

当前实测版本(用于排错对照)

  • Homebrew 5.1.1
  • node v24.14.1
  • pnpm 11.1.2
  • uv 0.8.14
  • go 1.24.1 (darwin/arm64)

文件位置

  • ~/.zshrc 主配置(见第 4 节全文)
  • ~/.zshenv 内容:. "$HOME/.cargo/env"
  • ~/.zprofile 内容:eval "$(/opt/homebrew/bin/brew shellenv)"
  • ~/.p10k.zshp10k configure 生成,体积约 90KB,可选择从旧机带过来

3. 配置里几个”非显然”的设计

把这些写进 .zshrc 是踩过坑后的成品,迁移时不要轻易删:

  1. P10k instant prompt 必须在文件最顶 提示符立即显示,其余 zshrc 在后台加载。删掉会拖慢启动 ~300 ms。

  2. zstyle ':omz:update' mode disabled + ZSH_DISABLE_COMPFIX=true 关掉 omz 自动更新检查、跳过 compfix 审计,启动再省 ~150 ms。

  3. Terminal theme-report stripping (_disable_terminal_theme_reports) Ghostty / Kiro / cmux 这几个终端会发 ^[?2031l 主题查询序列,泄露到 prompt 会让 P10k 报 “console output” 警告。这段 hook 把首屏跳过、之后逐次清理。

  4. nvm lazy-load nvm.sh 加载要 2 秒,所以我只在 PATH 里塞 default 版本的 bin。真正调用 nvm 命令时再 source 真身。99% 场景不会触发。

  5. Homebrew USTC 镜像 国内不走镜像 brew update 必卡。HOMEBREW_AUTO_UPDATE_SECS=31536000 把自动更新拉到一年一次。

  6. uv 接管 pip / venv alias pip='uv pip'alias venv='uv venv' 让肌肉记忆无缝迁移。

  7. claude-upgrade 辅助函数 pnpm v11 isolated layout 有 bug,装 @anthropic-ai/claude-codeinstall.cjs 会写一个 500B 的桩文件,而不是 198M 的真实二进制。这个函数装完后重新跑一次 install.cjs 修复。

  8. Kiro 集成 只在 TERM_PROGRAM == kiro 时加载,不污染其它终端。


4. ~/.zshrc 全文

直接覆盖到 ~/.zshrc 即可。

# =============================================================================
# Powerlevel10k Instant Prompt — MUST be at the top
# =============================================================================
# Lets the prompt appear immediately while the rest of zshrc loads in background.
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

# =============================================================================
# Oh My Zsh + Powerlevel10k
# =============================================================================
export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME="powerlevel10k/powerlevel10k"

# Skip omz auto-update check on startup (run `omz update` manually when needed)
zstyle ':omz:update' mode disabled

# Skip compfix audit (we trust our completions; saves ~150 ms)
ZSH_DISABLE_COMPFIX=true

plugins=(
  git
  zsh-syntax-highlighting
  zsh-autosuggestions
)

source $ZSH/oh-my-zsh.sh

# Powerlevel10k user config (created by `p10k configure` wizard).
[[ -f ~/.p10k.zsh ]] && source ~/.p10k.zsh

# =============================================================================
# Terminal theme-report stripping (Ghostty / Kiro / cmux compatibility)
# =============================================================================
typeset -g _DTR_FIRST_DONE=
function _disable_terminal_theme_reports() {
  [[ -o interactive ]] || return 0
  # Skip the first precmd: it fires inside P10k's instant-prompt capture
  # window and the escape would trip the "console output" warning.
  if [[ -z $_DTR_FIRST_DONE ]]; then
    _DTR_FIRST_DONE=1
    return 0
  fi
  printf '\e[?2031l'
}

function _strip_terminal_theme_report_and_accept_line() {
  local compact="$BUFFER"
  compact=${compact// /}
  compact=${compact//$'\t'/}
  compact=${compact//$'\r'/}
  compact=${compact//$'\n'/}

  if [[ "$compact" =~ '^(\??997;[12]n)+$' ]]; then
    BUFFER=""
    CURSOR=0
    zle redisplay
    return 0
  fi

  zle .accept-line
}

autoload -Uz add-zsh-hook
if [[ -o interactive ]]; then
  add-zsh-hook precmd _disable_terminal_theme_reports
  zle -N accept-line _strip_terminal_theme_report_and_accept_line
fi

# =============================================================================
# Homebrew (China mirrors via USTC)
# =============================================================================
export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git"
export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git"
export HOMEBREW_API_DOMAIN="https://mirrors.ustc.edu.cn/api/homebrew/core"
export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.ustc.edu.cn/homebrew-bottles"
export HOMEBREW_AUTO_UPDATE_SECS=31536000

# =============================================================================
# Node via NVM — lazy-load
# =============================================================================
# Strategy: prepend the default node version's bin to PATH so node/npm/npx
# work instantly. Only when you actually call `nvm` itself does nvm.sh load
# (saves ~2000 ms of startup). 99% of users never call nvm directly.
export NVM_DIR="$HOME/.nvm"

# Resolve default version alias to a concrete version dir
__nvm_default_alias=$(<"$NVM_DIR/alias/default" 2>/dev/null)
if [ -n "$__nvm_default_alias" ]; then
  if [[ "$__nvm_default_alias" == v* ]]; then
    __nvm_default_version="$__nvm_default_alias"
  else
    __nvm_default_version=$(ls -1 "$NVM_DIR/versions/node" 2>/dev/null \
      | grep "^v${__nvm_default_alias}" | sort -V | tail -1)
  fi
  if [ -n "$__nvm_default_version" ] \
     && [ -d "$NVM_DIR/versions/node/$__nvm_default_version/bin" ]; then
    export PATH="$NVM_DIR/versions/node/$__nvm_default_version/bin:$PATH"
  fi
fi
unset __nvm_default_alias __nvm_default_version

# Lazy nvm: first call to `nvm` sources nvm.sh, then re-runs the call
nvm() {
  unset -f nvm
  [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
  [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
  nvm "$@"
}

# =============================================================================
# Go
# =============================================================================
export GOPATH="$HOME/go"
export PATH="$PATH:$GOPATH/bin"

# =============================================================================
# uv (Python — replaces pip in muscle memory)
# =============================================================================
[ -s "$HOME/.local/bin/env" ] && . "$HOME/.local/bin/env"
alias pip='uv pip'
alias venv='uv venv'

# =============================================================================
# Bun
# =============================================================================
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"
[ -s "$HOME/.bun/_bun" ] && source "$HOME/.bun/_bun"

# =============================================================================
# Antigravity
# =============================================================================
export PATH="$HOME/.antigravity/antigravity/bin:$PATH"

# =============================================================================
# pnpm
# =============================================================================
export PNPM_HOME="$HOME/Library/pnpm"
case ":$PATH:" in
  *":$PNPM_HOME:"*) ;;
  *) export PATH="$PNPM_HOME:$PATH" ;;
esac

# =============================================================================
# Kiro IDE shell integration (only when running inside Kiro)
# =============================================================================
[[ "$TERM_PROGRAM" == "kiro" ]] && . "$(kiro --locate-shell-integration-path zsh)"

# =============================================================================
# Miniforge / conda — Python ecosystem
# =============================================================================
export MINIFORGE_HOME="$HOME/miniforge3"
export MINIFORGE_PYTHON="$MINIFORGE_HOME/bin/python"
export PIPX_DEFAULT_PYTHON="$MINIFORGE_PYTHON"
export UV_PYTHON="$MINIFORGE_PYTHON"

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/weigao/miniforge3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/Users/weigao/miniforge3/etc/profile.d/conda.sh" ]; then
        . "/Users/weigao/miniforge3/etc/profile.d/conda.sh"
    else
        export PATH="/Users/weigao/miniforge3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

# =============================================================================
# claude-code upgrade helper
# =============================================================================
# Works around pnpm v11 isolated-layout bug where install.cjs writes a 500B
# stub instead of the 198M native binary. Re-running install.cjs after install
# completes fixes it.
claude-upgrade() {
  pnpm i -g @anthropic-ai/claude-code "$@" || return
  local installer
  installer=$(find ~/Library/pnpm/global -path '*claude-code/install.cjs' 2>/dev/null | head -1)
  if [ -n "$installer" ]; then
    node "$installer"
  fi
  command claude --version
}

5. ~/.zshenv~/.zprofile

# ~/.zshenv
. "$HOME/.cargo/env"
# ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

6. 手动安装命令(Claude Code 失败时备用)

# 1. Homebrew(先 export 镜像变量再装,否则会卡 GitHub)
export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git"
export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 2. Oh My Zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended

# 3. Powerlevel10k + 两个插件
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git \
  ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
git clone https://github.com/zsh-users/zsh-autosuggestions \
  ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git \
  ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting

# 4. Nerd Font(P10k 图标)
brew install --cask font-fira-code-nerd-font

# 5. nvm + node
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
nvm install --lts && nvm alias default lts/*

# 6. uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# 7. bun
curl -fsSL https://bun.sh/install | bash

# 8. pnpm / go
brew install pnpm go

# 9. miniforge
brew install --cask miniforge
conda init zsh

# 10. 覆盖 ~/.zshrc 为本文档第 4 节内容,然后
exec zsh
p10k configure   # 走一遍向导,生成 ~/.p10k.zsh

7. 善后检查清单

  • echo $SHELL/bin/zsh
  • 终端用了 Nerd Font(否则 P10k 图标会乱码)
  • which node 指向 ~/.nvm/versions/node/v*/bin/node
  • which python 指向 conda env,uv --version 可用
  • claude-upgrade 函数可调用(type claude-upgrade
  • 启动时间合理:time zsh -i -c exit < 300 ms
修改历史1 次提交

相关阅读

基于标签与分类