技术解析
z.lua 是一个快速路径切换工具,它会跟踪你在 shell 下访问过的路径,通过一套称为 Frecent 的机制(源自 FireFox ),经过一段简短的学习之后,z.lua 会帮你跳转到所有匹配正则关键字的路径里 Frecent 值最高的那条路径去。
正则将按顺序进行匹配,"z foo bar" 可以匹配到 /foo/bar,但是不能匹配 /bar/foo。
项目地址:skywind3000/z.lua
Posix Shells ( Bash、zsh、dash、sh 或 BusyBox 等)中,在你的 .bashrc
, .zshrc
或者 .profile
文件中按 shell 类型添加对应语句:
eval "$(lua /path/to/z.lua --init bash)" # BASH 初始化
eval "$(lua /path/to/z.lua --init zsh)" # ZSH 初始化
eval "$(lua /path/to/z.lua --init posix)" # Posix shell 初始化
用下面参数初始化会进入“增强匹配模式”:
eval "$(lua /path/to/z.lua --init bash once enhanced)" # BASH 初始化
eval "$(lua /path/to/z.lua --init zsh once enhanced)" # ZSH 初始化
eval "$(lua /path/to/z.lua --init posix once enhanced)" # Posix shell 初始化
同时 zsh 支持 antigen/oh-my-zsh 等包管理器,可以用下面路径:
skywind3000/z.lua
进行安装,比如 antigen 的话,在 .zshrc
中加入:
antigen bundle skywind3000/z.lua
就可以了(主要要放在 antigen apply 语句之前)。Windows 和 Fish Shell 的初始化见文档。
z.lua 提供两种路径匹配算法:
除了设置环境变量外,还可以通过:
eval "$(lua /path/to/z.lua --init bash enhanced)"
来进入增强模式。
默认情况下 z.lua 使用和 z.sh 类似的匹配算法,成为默认匹配法。给定路径会按顺序匹配各个正则表达式。
cd 到一个包含 foo 的路径:
z foo
cd 到一个以 foo 结尾的路径:
z foo$
使用多个参数进行跳转:
假设路径历史数据库(~/.zlua )中有两条记录:
10 /home/user/work/inbox
30 /home/user/mail/inbox
"z in"
将会跳转到 /home/user/mail/inbox
因为它有更高的权重,同时你可以传递更多参数给 z.lua 来更加精确的指明,如 "z w in"
则会让你跳到 /home/user/work/inbox
。
你可以通过设置环境变量来启用增强匹配模式:
export _ZL_MATCH_MODE=1
或者使用下面语句:
eval "$(lua /path/to/z.lua --init bash enhanced)"
进行初始化,他们是等效的,记得把上面的 bash 可以根据你的 shell 改为 zsh
或者 posix
。
对于一个给定的正则关键字序列(即 z 命令后面的参数),某路径有且只有满足下面两个条件才算作 “匹配成功”:
如果两条规则同时启用找不到任何结果,那么将会退回到只用规则 1 进行筛选,这两条规则是参考 fasd 引入的。
匹配路径名的最后一段:
假设数据库内容为:
10 /home/user/workspace
20 /home/user/workspace/project1
30 /home/user/workspace/project2
40 /home/user/workspace/project3
在增强模式下使用 "z wo"
的话,只有 /home/user/work
满足匹配,因为按照第二条规则,这是唯一一条最有一段名称匹配 wo
的路径。
因为最后一级目录名称总是最容易记住的,所以给到它比较高的优先级。在默认匹配算法中,你同样可以用 "z space$"
来达到相同的目的,但是 "z wo"
可以打更少的字。
小技巧:
"z wo $"
"z wo /"
。如果没法匹配,同时又存在一条路径名和关键字相同,那么 cd 过去:
有时候如果你输入:
z foo
但是数据库里又没有任何匹配 foo 的记录,然后却存在一个可以在当前位置访问的目录,刚好名字是 "foo",那么 "z foo
" 的效果将会和下面的命令效果相同:
cd foo
因此,在增强匹配算法中,你总可以象 cd 命令一样使用 z 命令,而不必当心目标路径是否被记录过。
忽略当前路径:
如果你使用 z xxx
但是当前路径恰好是最佳匹配结果,那么 z.lua 会使用次优结果进行跳转。假设有如下数据:
10 /Users/Great_Wall/.rbenv/versions/2.4.1/lib/ruby/gems
20 /Library/Ruby/Gems/2.0.0/gems
默认情况下,当我使用 z gems
时,我会被带到 /Library/Ruby/Gems/2.0.0/gems
,因为它有更高权重,但是可能并不是我想要去的地方,这时我按一下方向键上键,再次执行 z gems
,那么我就能被带到 /Users/Great_Wall/.rbenv/versions/2.4.1/lib/ruby/gems
目录中,而这正是我想去的地方。
我当然可以每次使用z env gems
来精确指明,但是每当我输入 z xxx
我必然是想进行路径跳转的,而不是呆在原地,所以使用增强匹配模式,即便当前目录是最佳匹配,它也能懂得你想跳转的心思。
再我最初实现 z.lua 时,只有一个和 z.sh 类似的默认匹配算法,在网友的建议下,我陆续学习了来自 fasd / autojump 中的优秀理念,并加以完善改进,成为如今集三家之长的 “增强匹配算法” ,给它取个昵称,叫做 “更懂你的匹配算法”。
何时更新数据呢?默认情况下,z.lua 会在每次显示命令提示符时记录当前路径(和 z.sh 一致),但是还提供了一个 $_ZL_ADD_ONCE 的环境变量选项,设置成 1 的话,只有当前路径改变,才会将新路径添加到数据库。
除了设置环境变量外,不同的 shell 下还可以在初始化时增加 "once" 参数来达到相同目的,比如:
eval "$(lua /path/to/z.lua --init bash once enhanced)"
eval "$(lua /path/to/z.lua --init zsh once enhanced)"
lua /path/to/z.lua --init fish once enhanced | source
将会同时启用增强匹配算法和 once 机制,在一些比较慢的硬件下(路由器,cygwin,msys ),使用该机制将有效的提升性能。其实 autojump 在 zsh 下会使用类似 once 的机制,而 bash 下则和 z.sh 类似。
从效果上来讲,z.sh 的模式(关闭 once )强调的是 “在某路径下工作的时间长短”,而 autojump 的模式(启用 once )则强调 “进入某路径的次数多少”。
使用 -i 参数进行跳转时, 如果有多个匹配结果,那么 z.lua 会给你显示一个列表:
$ z -i soft
3: 0.25 /home/data/software
2: 3.75 /home/skywind/tmp/comma/software
1: 21 /home/skywind/software
> {光标位置}
然后你按照最前面的序号输入你想要去的地方,比如输入 3 就会进入 /home/data/software
。如果你不输入任何东西直接按回车,那么将会直接退出而不进行任何跳转。
推荐一些常用的命令别名:
alias zc='z -c' # 严格匹配当前路径的子路径
alias zz='z -i' # 使用交互式选择模式
同时你可以定义一个名为 zf
的命令,搭配 fzf 进行历史路径模糊匹配:
alias zf='cd "$(z -l -s | fzf --reverse --height 35%)"'
最慢的部分当然是添加当前路径到数据库。该操作会在每次你按回车时执行,所以我在我的 Nas 上做了个对比:
$ time autojump --add /tmp
real 0m0.352s
user 0m0.077s
sys 0m0.185s
$ time fasd -A /tmp
real 0m0.618s
user 0m0.076s
sys 0m0.242s
$ time _z --add /tmp
real 0m0.194s
user 0m0.046s
sys 0m0.154s
$ time _zlua --add /tmp
real 0m0.052s
user 0m0.015s
sys 0m0.030s
可以看出,z.lua 是消耗资源最少,并且最快的,可以更流畅的在性能不好的环境中使用。
真的可以卸载 autojump / z / fasd 了。