跳转到内容

zoxide — 学会你常去哪的智能 cd

是什么

zoxide 是一个会记住你常去哪些目录的 cd 替代品。日常类比:像浏览器地址栏——你输 “git” 它就把 github.com 排第一,因为你天天去;冷门网站再准也排不到前面。

你写:

Terminal window
z proj

它从你过去 cd 过的所有目录里,挑一个 最常去 + 最近去过 + 名字带 “proj” 的,直接跳过去。等价于你手敲:

Terminal window
cd /Users/jason/code/big-project/services/api

底层是 Rust 单二进制 + 一个 SQLite-like 小数据库(默认在 ~/.local/share/zoxide/db.zo,存”路径、访问次数、最后访问时间”三元组)。第一次用要先 cd 一遍学路径,之后就只敲关键词。

为什么重要

不理解 zoxide,下面这些事都没法解释:

  • 为什么 dotfiles 仓库里几乎每个高 star 模板都默认装它,把 cd 直接 alias 成 z
  • 为什么 z.sh / autojump 这两个老 shell 脚本被 Rust 党集体抛弃——同一个想法 zoxide 启动只要 5ms,老脚本要 100ms+
  • 为什么 “frecency” 这个词从 Firefox 地址栏走出来,变成 CLI 工具圈的标配排序术语
  • 为什么 z foo 偶尔跳错地方——它不是按字母序,是按你”过去用得多不多 + 最近用没用”

核心要点

zoxide 的工作可以拆成 三步

  1. 学习:你每 cd 一次,zoxide 把目标路径写进数据库,访问次数 +1,时间戳更新。类比:地址栏每次你点过的网址都加 1 分。

  2. 打分:你输 z foo,zoxide 把所有路径名含 “foo” 的记录拿出来,按 frecency 公式打分——访问越多、越新近、关键词越匹配,分越高。然后 cd 到分最高的。

  3. 衰减:老条目分数随时间慢慢掉。数据库默认上限 10000 条,超了把分最低的清掉。所以三个月没去的目录会自然消失——不需要你手动维护。

三步加起来就是 frecency = frequency × recency:常去的 + 最近去过的,权重最高。

实践案例

案例 1:装上、初始化、第一次用

Terminal window
brew install zoxide # macOS
echo 'eval "$(zoxide init zsh)"' >> ~/.zshrc
source ~/.zshrc
cd ~/code/big-project # 先 cd 一次让它学
cd ~ # 回家
z proj # 跳回 ~/code/big-project

zoxide init zsh 不是装包,是让 zoxide 把 z / zi 这两个 shell 函数注入到当前 shell。没 eval 这一步,命令行只有 zoxide 二进制能用,不会有 z 这个简短入口。

每个 shell 注入的函数体长这样(zoxide init 输出,简化版):

Terminal window
function z() {
local result=$(zoxide query --exclude "$PWD" -- "$@")
cd "$result"
}

也就是说 z 等同于”问 zoxide 一句、cd 过去”,逻辑全在 zoxide 二进制里,shell 只剩一层薄壳。

案例 2:多关键词消歧

Terminal window
# 你有两个目录都带 'foo':~/work/foo 和 ~/notes/foo-archive
z foo # 跳分最高的那个(看 frecency)
z work foo # 同时匹配两个关键词,必须同时出现在路径里
z notes foo # 强制跳另一个

多个候选时 zoxide 不会乱猜,关键词越多越精准。

案例 3:zi 交互模式(配合 fzf)

Terminal window
zi proj

弹出 fzf 选单,把所有匹配 “proj” 的目录按 frecency 排好让你看。再输几个字过滤,回车跳。

适合你不确定排第一的是不是想要的那个——比 z 更安全,比 cd 更快。日常工作流:

  • 频繁去的 5 个目录用 z 关键词(盲打最快)
  • 偶尔去的、记不清完整名字的用 zi 关键词(fzf 选)
  • 全新目录或临时去一次用普通 cd(不污染数据库也行)

踩过的坑

  1. 没在 rc 里 eval zoxide init:装了 zoxide 二进制但 shell 里 z 命令找不到——zoxide 不是 alias,是 init 时动态注入的 shell 函数,必须 eval "$(zoxide init zsh)" 才生效。

  2. 第一次用直接 z foo 报 no match:数据库是空的,zoxide 没有”扫盘”功能,必须靠你 cd 一次次教。前两天会觉得它没用,过一周才显威力。

  3. 多个候选时跳错:z 默认只返回 top-1,不是字母序最近的。想看所有候选用 zi(fzf 选单),不要硬猜。

  4. z.sh 和 zoxide 同时装:两个都注册 z 函数,后 init 的覆盖先 init 的,但数据库不互通——历史记录只在一个里。装 zoxide 前先把 .zshrc 里 z.sh 的 source 注释掉。zoxide 自带 zoxide import 子命令可以把老 z.sh / autojump 的库导过来,别白白丢了几个月的训练数据。

适用 vs 不适用场景

适用

  • 经常在 5-50 个固定项目目录间跳来跳去(前端 monorepo / 多服务后端 / 学习仓库)
  • 习惯命令行多于 GUI 文件管理器,cd 是你最高频命令之一
  • 喜欢 Rust 工具链(fd / ripgrep / bat / eza / sd)的零依赖单二进制风格

不适用

  • 你的目录每天都在变(临时容器、CI 沙箱)——zoxide 学不到稳定模式
  • 你只在 1-2 个目录工作,cd 一次就不出来——上 zoxide 是杀鸡用牛刀
  • 你需要跳到从没去过的新目录——zoxide 不会魔法,必须先 cd 学一次
  • 你的 shell 是非主流(rc / xonsh 早期版本)——init 模板可能不存在

历史小故事(可跳过)

  • 2006 年:Firefox 2.0 引入 frecency 地址栏排序——访问次数 × 时间衰减。那时还没人想到把这思路搬到 shell。
  • 2009 年:rupa 写 z.sh(500 行 bash),第一次让 shell 有 frecency 跳转。慢,但能用。
  • 2010 年:wting 用 Python 写 autojump,加了模糊匹配和数据库。比 z.sh 快但启动还是慢(Python 解释器冷启)。
  • 2018 年:Ajeet D’Souza 用 Rust 重写成 zoxide。启动从 100ms 降到 5ms,零依赖单二进制,覆盖 5 种 shell。
  • 2022 年起:被几乎所有热门 dotfiles 模板默认装上,事实上替代了 z.sh。
  • 2026 年现在:22k+ star,社区把它当 “cd 默认替代” 来推荐,初学 Linux 的教程开始把 zoxide 写进第一周配置。

学到什么

  1. frecency 是个跨领域工程模式——浏览器、编辑器最近文件、IDE 跳转、CLI 跳转,全都用它
  2. shell 函数注入是 CLI 工具的常见落地方式——eval 一行字符串往当前 shell 塞函数,不需要修改 shell 本身
  3. Rust 重写老 shell 工具是 2018-2024 的大潮——启动延迟和单二进制分发是核心吸引力
  4. 数据库要有衰减机制——否则一年后排第一的还是你大学时打开过 200 次的那个目录

延伸阅读

关联

  • fzf —— zi 子命令直接 pipe 到 fzf 出选单
  • fd —— 同生态 Rust 重写——find → fd,cd → zoxide
  • ripgrep —— Rust 重写老工具的开山之作,zoxide 受它影响
  • bat —— Rust 重写 cat,同生态零依赖单二进制
  • eza —— Rust 重写 ls,常和 zoxide 一起出现在 dotfiles
  • sd —— Rust 重写 sed,同款”小工具单一职责”哲学

反向链接

  • bat —— bat — 现代 cat 替代
  • broot —— broot — 把 tree 命令升级成会过滤、能 cd、显大小、看 git 的交互树
  • btop —— btop — bashtop 三代 C++ 版,五面板一屏的彩色资源监控器
  • eza —— eza — 现代 ls 替代(exa 的社区接管 fork)
  • fzf —— fzf — 命令行模糊查找
  • htop —— htop — top 的彩色交互替代(鼠标点选 / 树视图 / 过滤)
  • lazygit —— lazygit — Go 写的全功能 git TUI,键盘驱动 stage / rebase / cherry-pick
  • ripgrep —— ripgrep — Rust 写的现代 grep
  • sd —— sd — 直觉语法的 sed 替代品(Rust 写的 find-and-replace)