zoxide 是一个「更聪明的 cd」。你在终端里 cd 过的目录它会记下来并按访问次数排序,之后输入 z 关键词 就能直接跳过去,不用敲完整路径。Rust 写的单文件 exe,数据库就是一个几 KB 的文本文件。

它不是全盘搜索,只认你真正进去过的目录。这一点决定了它的行为和你的预期可能不一样:实测 18 个目录里,查中间的层级名一个都查不到,只有叶子目录才命中。

装法:一个 exe 加一行 init

zoxide --version
zoxide 0.10.0

zoxide init powershell     # 输出 4312 字符、132 行
zoxide init bash           # 输出 6285 字符、181 行

Release 页给的是 zip,解压出一个 zoxide.exe,1261568 字节,不到 1.3 MB,没有运行库依赖。init 生成的是 shell 钩子脚本:它把 cd 换成自己的函数,每次切换目录时顺手把路径记进数据库,同时定义 z 和 zi 两个命令。

钩子脚本要加进 shell 的启动文件,重开终端才生效。PowerShell 放在 $PROFILE,bash 放 .bashrc。

建 18 个目录,看能查到几个

造一棵有辨识度的目录树,逐个 zoxide add 进去,再拿关键词查:

关键词命中条数第一条结果
front1frontend
ref1reference
q31q3
podcast1podcast
ios1ios
web0无
data0无

「web」和「data」查不到,因为它们是中间层:数据库里存的是 projects\web\frontend 这种完整路径,但匹配是按路径尾部做的,中间的一段不能单独命中。想让「web」能跳,得给它一个自己的目录并 add 进去。

这个设计有它的道理:z 的目的是「跳到我常去的那个地方」,而不是「按前缀找目录」。要按名字搜整棵树,fd 或 fzf 更合适。

常去的目录自动排前面

同一个关键词命中多个时,按 rank 排序。rank 由访问次数和最近一次访问时间共同决定,反复进出会加分。实测里给 projects\web\frontend 加了 6 次、docs\api\reference 加了 4 次之后,查「front」和「ref」都能直接拿到想要的那个。

zoxide query -l 关键词 会列出所有命中项而不只是第一条,脚本里做排除或者看候选很好用。

比 cd 慢,但要看你跟什么比

指标数值
一次 query 耗时(20 次平均)172.8 毫秒
最快 / 最慢156.8 / 207.5 毫秒
18 条记录的数据库1190 字节
exe 体积(字节)1261568
对照:同机起一个 shell 进程142.8 毫秒

172.8 毫秒这个数字看着吓人,但其中约 140 毫秒是 Windows 启动进程的固定成本(同机测 cmd 本身就要 142.8 毫秒),真正读数据库和算 rank 的时间只有几十毫秒。数据库 1190 字节,18 条记录,读完就是一次文件读取的事。

实际使用中这 172.8 毫秒被 shell 钩子吃掉了:z 是命令替换,跑完才 cd,所以你能感知到的停顿就是这一下。习惯之后可以接受,但如果你在写循环里反复 cd,累积会明显。

查不到时给的是退出码

> zoxide query zzz
(标准输出为空)
zoxide: no match found
退出码 1

> zoxide add D:\no-such-dir
zoxide: not a directory: D:\no-such-dir
退出码 1

没有匹配时错误写在 stderr,stdout 是空的,退出码 1。脚本里可以直接判断。add 一个不存在的目录同样退出码 1,不会悄悄建一条无效记录。

有个地方要留意:zoxide query ""(空字符串)不报错,退出码 0,直接返回 rank 最高的那个目录。所以别用空参数做「无输入 = 不跳转」的判断,会跳到意料之外的地方。

适合和不适合

目录层级深、名字记得住。要跳的目录有辨识度,z 项目名 一次到位,比敲 cd ../../.. 强得多。

想在多个 shell 间共享历史。数据库是一个文件,PowerShell、bash、Git Bash 都在往里写,换终端不用重新积累。

需要按名字搜索没去过的目录。它只认 add 过的路径,没进过的目录永远查不到,这一块交给 fd。

在脚本里大量 cd。每次 172.8 毫秒,循环一百次就是 17 秒。脚本里该用绝对路径。

还没测的两项:数据库涨到一万条后的查询耗时 / 多个 shell 同时写数据库会不会冲突。前者要造大量记录,后者要开几个终端并发压。