---
title: Zsh 环境
url: https://doc.liz6.com/tools/shell
locale: zh
area: tools
tags:
- tools
date: null
modified: 2026-06-30
description: zsh 里唯一值得写的是补全 —— 原生打底、carapace 兜底、fzf-tab 按命令给预览。
---

# Zsh 环境

zsh 这套两百来行,提示符是 starship,别名一堆,但这些都没什么好说的。唯一花了心思、也唯一值得写的是**补全**——我把 Tab 调成了带预览的选单,而且为此跟 carapace 较了点劲。

补全的优先级是:原生 `compinit` 打底,carapace 只兜底。这个顺序很重要。carapace 默认初始化会 `compdef` 接管七百多个命令,听着省事,实则把 zsh 原生那套更细的补全、以及 fzf-tab 依赖的子命令上下文(比如 `git checkout` 要按分支给预览)全盖掉了。所以我把它的 compdef 滤掉,只在原生补全交白卷时才轮到它:

```zsh
source <(carapace _carapace zsh | grep -v '^compdef ')
zstyle ':completion:*' completer _complete _carapace _ignored
```

补好之后,fzf-tab 把候选丢进 fzf,并按命令给不同预览:文件用 bat 渲、目录用 eza 列、`kill` 显示进程、`systemctl` 直接出 unit 状态、`git checkout` 列最近几条提交、`git add` 显示 diff。这是日常体感提升最大的一块——很多时候不用敲完命令再回车看结果,Tab 一下预览就够判断了。

```zsh
zstyle ':fzf-tab:complete:systemctl:*' fzf-preview 'systemctl status --no-pager $word | head -30'
zstyle ':fzf-tab:complete:git-(checkout|switch):*' fzf-preview 'git log --oneline -n 5 $word'
```

这套 preview 看着光鲜,坑也不少,我都写进注释了:给 fzf 一个不认识的 flag 会让它直接退出、补全列表莫名变空;`fzf-min-height` 留太大,候选少时底下空一截。所以那些 `--no-sort`、`fzf-pad 0` 不是抄来的,是调出来的。

补全之外,还有几件让 shell"跟手"的小事,各说一句:

**zsh-autosuggestions** 给 fish 那种历史灰字提示——敲一半,它把最近匹配的整条命令以灰字补在后面,`→` 或 `Ctrl+f` 接受。它异步取建议(`ZSH_AUTOSUGGEST_USE_ASYNC`),所以再长的历史也不卡键。

**zsh-syntax-highlighting** 边敲边校验:命令存在标绿、不存在标红、引号没闭合当场变色,回车前就能看出拼错。它**必须在 `.zshrc` 最后 source**——它要包在所有 ZLE 部件的最外层 hook 上,提前加载会被后面的插件覆盖掉。

**starship** 当提示符:单一 TOML 配置、跨 shell 通用,按目录上下文显示 git 分支/状态、语言版本、k8s context 这些,只在相关时出现,不常驻刷屏。

**ssh 补全**改了来源:默认会去翻 `known_hosts`(一堆 IP、还可能是 hash 过的没法读),我把它换成只从 `~/.ssh/config` 的 `Host` 别名补全,`ssh <TAB>` 直接列出我起过名的机器,连谁一目了然。

`zoxide` 的 `z` 跳目录、`ls` 全家换 eza、git pager 用 delta,这几样的细节都归到 [CLI 工具箱](cli-toolbox.md) 那边讲。
