编辑
2026-05-17
Linux
00

目录

服务器 zsh 环境配置记录:Zim + p10k + eza + zoxide
字体
配置文件
.zshenv
.zimrc
.zshrc
踩坑记录
启动时 compinit 重复初始化
Windows 编辑配置文件导致 CRLF 污染
Zim 安装脚本不能用 | bash 执行
一键部署
验收

服务器 zsh 环境配置记录:Zim + p10k + eza + zoxide

记录从零搭建服务器 zsh 环境的过程,包含踩过的坑。配置已整理成 dotfiles 仓库,新服务器一键部署。

环境:Ubuntu 24.04 / Debian 12,zsh + Zim 框架

最终工具栈

工具作用
Zimzsh 框架,比 oh-my-zsh 轻,启动快
Powerlevel10k提示符主题
eza带图标的 ls 替代,支持 git 状态列
zoxide智能目录跳转,记住历史,z 关键词 直达
fzf模糊查找,Ctrl+R 历史搜索、Ctrl+T 文件选择
bat带语法高亮的 cat(Debian/Ubuntu 上命令名为 batcat)

字体

先做这一步,否则 eza 图标会显示成方块。

eza 的图标由本地终端渲染,服务器不需要装字体。SSH 连服务器时,字符渲染在本地做,改的是本地终端的字体配置。

下载 0xProto Nerd Fontnerdfonts.com

装完在终端设置里切换字体。Windows Terminal 注意:每个 profile 可以单独设字体,改的要是你 SSH 用的那个 profile,不是默认 profile。


配置文件

.zshenv

/etc/zsh/zshrc 更早加载,用来解决 compinit 重复初始化的问题(见下方坑点记录)。

zsh
skip_global_compinit=1

.zimrc

bash
# 基础模块 zmodule environment zmodule input zmodule termtitle zmodule utility # Git zmodule git zmodule wfxr/forgit # fzf 加持的 git 交互工具 # 主题 zmodule duration-info zmodule git-info zmodule romkatv/powerlevel10k # 补全(必须在普通模块之后) zmodule zsh-users/zsh-completions --fpath src zmodule completion # 必须最后加载 zmodule zsh-users/zsh-syntax-highlighting zmodule zsh-users/zsh-history-substring-search zmodule zsh-users/zsh-autosuggestions

.zshrc

bash
# ========================= # ZSH CONFIG # ========================= # p10k 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 # Zim 初始化 ZIM_HOME=${ZDOTDIR:-$HOME}/.zim source ${ZIM_HOME}/init.zsh # 基础环境变量 export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 export EDITOR=vim export VISUAL=vim # 历史记录 HISTSIZE=50000 SAVEHIST=50000 HISTFILE=~/.zsh_history setopt APPEND_HISTORY setopt SHARE_HISTORY # 跨会话共享 setopt HIST_IGNORE_ALL_DUPS # 去重 setopt HIST_REDUCE_BLANKS setopt HIST_IGNORE_SPACE # 空格开头不入历史(用于敏感命令) # 补全 setopt AUTO_MENU setopt COMPLETE_IN_WORD # 目录 setopt AUTO_CD # p10k 主题 [[ -f ~/.p10k.zsh ]] && source ~/.p10k.zsh # ---------------------------- # Aliases # ---------------------------- # eza alias ls='eza --icons --group-directories-first' alias ll='eza -alF --icons --group-directories-first --git --header --time-style=relative' alias la='eza -A --icons --group-directories-first' alias l='eza --icons --group-directories-first' alias lt='eza --tree --icons --level=2' alias lt3='eza --tree --icons --level=3' # bat alias cat='batcat --paging=never' alias bat='batcat' # 目录跳转 alias ..='cd ..' alias ...='cd ../..' # 危险操作加确认(服务器上手滑代价大) alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' # grep alias grep='grep --color=auto' # Git alias gs='git status' alias ga='git add' alias gc='git commit' alias gp='git push' alias gl='git log --oneline --graph --decorate' # Docker alias dps='docker ps' alias dpa='docker ps -a' alias di='docker images' alias dlog='docker logs -f' alias dex='docker exec -it' # Systemd alias sctl='systemctl' alias sstart='systemctl start' alias sstop='systemctl stop' alias sstat='systemctl status' alias srestart='systemctl restart' # Network alias ports='ss -tulnp' alias myip='curl -s --max-time 5 ifconfig.me' # Process alias psg='ps aux | grep' # ---------------------------- # 性能 # ---------------------------- export KEYTIMEOUT=1 # ---------------------------- # 函数 # ---------------------------- # mkdir + cd mkcd() { mkdir -p "$1" && cd "$1" } # 通用解压 extract() { if [ ! -f "$1" ]; then echo "'$1' is not a valid file"; return 1; fi case "$1" in *.tar.bz2) tar xjf "$1" ;; *.tar.gz) tar xzf "$1" ;; *.tar.xz) tar xJf "$1" ;; *.tar) tar xf "$1" ;; *.bz2) bunzip2 "$1" ;; *.gz) gunzip "$1" ;; *.zip) unzip "$1" ;; *.7z) 7z x "$1" ;; *.rar) unrar x "$1" ;; *) echo "Unknown format: $1" ;; esac } # ---------------------------- # 工具初始化(放文件末尾) # ---------------------------- eval "$(zoxide init zsh)" source <(fzf --zsh)

踩坑记录

启动时 compinit 重复初始化

表现

warning: completion was already initialized before completion module. Will call compinit again.

同时 p10k 弹 instant prompt 警告——p10k 只是信使,检测到启动期间有输出就报警,真正的根因是上面那行。

根因

Ubuntu/Debian 的 /etc/zsh/zshrc 在系统层面调了一次 compinit,Zim 的 completion 模块又调一次,重复了。

定位方法:

bash
zsh -xic exit 2>&1 | grep "compinit" | head

输出里能看到 +/etc/zsh/zshrc:111> compinit,确认是系统配置先调的。

解法

创建 ~/.zshenv,写入:

zsh
skip_global_compinit=1

.zshenv/etc/zsh/zshrc 更早加载。Debian/Ubuntu 的系统 zshrc 在调 compinit 前会检查这个变量,值为 1 就跳过。Zim 的 completion 模块成为唯一一次初始化,警告消失。

验证系统是否支持该变量:

bash
grep -n "skip_global_compinit" /etc/zsh/zshrc

有输出即支持。


Windows 编辑配置文件导致 CRLF 污染

表现

/home/csr/.zimrc:4: command not found: ^M fatal: unable to access 'https://github.com/zimfw/environment?.git/': URL rejected: Malformed input to a URL function

^M 是 Windows 的回车符 \rzmodule environment 变成了 zmodule environment\r,git clone 的 URL 里带了非法字符。

根因

在 Windows 上用编辑器(VS Code 默认)保存文件时,换行符是 CRLF(\r\n),Linux/zsh 需要 LF(\n)。

三层解法

  1. 编辑器层:VS Code 右下角点 CRLF 切成 LF 再保存
  2. 仓库层:加 .gitattributes,强制所有文件 LF
* text=auto eol=lf *.sh text eol=lf .zshrc text eol=lf .zimrc text eol=lf .zshenv text eol=lf

提交时加一步规范化:

bash
git add --renormalize .
  1. 部署层deploy() 函数里用 sed 在落盘前清洗
bash
sed 's/\r$//' "$src" > "$dst"

最后一道兜底,即使仓库里偶尔带了 \r,落到目标机器也是干净的。


Zim 安装脚本不能用 | bash 执行

表现

You must use zsh to run install.zsh curl: (23) Failure writing output to destination

根因

Zim 的安装脚本是 .zsh 文件,必须用 zsh 执行。| bash 会把脚本内容塞给 bash,bash 检测到不是 zsh 就退出,curl 那端管道断了所以报写入失败。

解法

先下载到临时文件,再明确用 zsh 执行:

bash
curl -fsSL https://raw.githubusercontent.com/zimfw/install/master/install.zsh \ -o /tmp/zim-install.zsh zsh /tmp/zim-install.zsh rm -f /tmp/zim-install.zsh

一键部署

配置托管在 GitHub:github.com/CasearF/dotfiles

新服务器部署:

bash
git clone https://github.com/CasearF/dotfiles.git ~/dotfiles cd ~/dotfiles && chmod +x install.sh && ./install.sh exec zsh

install.sh 自动完成:zsh/git/curl/unzip 检测安装 → eza/zoxide/fzf/bat 安装 → Zim 安装 → 旧配置备份(.bak-时间戳)→ 配置部署(自动清 CRLF)→ Zim 模块安装 → 设 zsh 为默认 shell。


验收

bash
exec zsh ll # eza:图标 + 目录排前 + git 列 z some-dir # zoxide:模糊跳转 Ctrl+R # fzf:历史模糊搜索 bat ~/.zshrc # bat:语法高亮

启动无 compinit 警告,五项全绿即完工。

本文作者:Casear

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

开往-友链接力