zoxide — 学会你常去哪的智能 cd
是什么
zoxide 是一个会记住你常去哪些目录的 cd 替代品。日常类比:像浏览器地址栏——你输 “git” 它就把 github.com 排第一,因为你天天去;冷门网站再准也排不到前面。
你写:
z proj它从你过去 cd 过的所有目录里,挑一个 最常去 + 最近去过 + 名字带 “proj” 的,直接跳过去。等价于你手敲:
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 的工作可以拆成 三步:
-
学习:你每 cd 一次,zoxide 把目标路径写进数据库,访问次数 +1,时间戳更新。类比:地址栏每次你点过的网址都加 1 分。
-
打分:你输
z foo,zoxide 把所有路径名含 “foo” 的记录拿出来,按 frecency 公式打分——访问越多、越新近、关键词越匹配,分越高。然后cd到分最高的。 -
衰减:老条目分数随时间慢慢掉。数据库默认上限 10000 条,超了把分最低的清掉。所以三个月没去的目录会自然消失——不需要你手动维护。
三步加起来就是 frecency = frequency × recency:常去的 + 最近去过的,权重最高。
实践案例
案例 1:装上、初始化、第一次用
brew install zoxide # macOSecho 'eval "$(zoxide init zsh)"' >> ~/.zshrcsource ~/.zshrc
cd ~/code/big-project # 先 cd 一次让它学cd ~ # 回家z proj # 跳回 ~/code/big-projectzoxide init zsh 不是装包,是让 zoxide 把 z / zi 这两个 shell 函数注入到当前 shell。没 eval 这一步,命令行只有 zoxide 二进制能用,不会有 z 这个简短入口。
每个 shell 注入的函数体长这样(zoxide init 输出,简化版):
function z() { local result=$(zoxide query --exclude "$PWD" -- "$@") cd "$result"}也就是说 z 等同于”问 zoxide 一句、cd 过去”,逻辑全在 zoxide 二进制里,shell 只剩一层薄壳。
案例 2:多关键词消歧
# 你有两个目录都带 'foo':~/work/foo 和 ~/notes/foo-archivez foo # 跳分最高的那个(看 frecency)z work foo # 同时匹配两个关键词,必须同时出现在路径里z notes foo # 强制跳另一个多个候选时 zoxide 不会乱猜,关键词越多越精准。
案例 3:zi 交互模式(配合 fzf)
zi proj弹出 fzf 选单,把所有匹配 “proj” 的目录按 frecency 排好让你看。再输几个字过滤,回车跳。
适合你不确定排第一的是不是想要的那个——比 z 更安全,比 cd 更快。日常工作流:
- 频繁去的 5 个目录用
z 关键词(盲打最快) - 偶尔去的、记不清完整名字的用
zi 关键词(fzf 选) - 全新目录或临时去一次用普通
cd(不污染数据库也行)
踩过的坑
-
没在 rc 里 eval zoxide init:装了 zoxide 二进制但 shell 里
z命令找不到——zoxide 不是 alias,是 init 时动态注入的 shell 函数,必须eval "$(zoxide init zsh)"才生效。 -
第一次用直接 z foo 报 no match:数据库是空的,zoxide 没有”扫盘”功能,必须靠你 cd 一次次教。前两天会觉得它没用,过一周才显威力。
-
多个候选时跳错:z 默认只返回 top-1,不是字母序最近的。想看所有候选用 zi(fzf 选单),不要硬猜。
-
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 写进第一周配置。
学到什么
- frecency 是个跨领域工程模式——浏览器、编辑器最近文件、IDE 跳转、CLI 跳转,全都用它
- shell 函数注入是 CLI 工具的常见落地方式——eval 一行字符串往当前 shell 塞函数,不需要修改 shell 本身
- Rust 重写老 shell 工具是 2018-2024 的大潮——启动延迟和单二进制分发是核心吸引力
- 数据库要有衰减机制——否则一年后排第一的还是你大学时打开过 200 次的那个目录
延伸阅读
- 官方 wiki:zoxide algorithm(讲 frecency 公式细节)
- 视频:YouTube — Why I replaced cd with zoxide
- 概念溯源:Mozilla Wiki — The Places frecency algorithm(Firefox 起源)
- fzf —— zi 交互模式背后的选单引擎
- fd —— 同 Rust CLI 工具圈的 find 替代品
关联
- 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)