智能补齐
昨天说完智能cd,今天来说说Bash下的智能补齐。跟Emacs1下的Anything.el / Helm.el一样,我们的补齐应该可以随意打几个词干,然后就把整条命令补出来。
与Bash自带的Ctrl-R / Ctrl-S历史命令搜索相比,它们开始匹配之后,要求必须 是连续地一直匹配下去,中间不能断,这对用户来说有点不够友好。而我的补齐 方式之下,用户可以提纲契领的输入几个信息量高的词干,从而保证一旦补齐之 后,会是唯一补齐,不需要进行多项选择;即使被迫需要多选,也可以做得比 Bash自带的更方便!
做法是这样,我写了一个空Bash函数,名为re,Re-Exec(再次执行)的意思,它
自己什么也不干,(除了把参数全丢掉——它的定义是 re () { true; }
),但
我为它写了Bash补齐命令才是窍门:-)
#!/bin/bash function _re() { local cur prev local IFS=$'\n' COMPREPLY=() set -- "${COMP_WORDS[@]}" shift COMPREPLY=( $(skeleton_compgen_word.pl \ -d '\n' -p \; -f ~/.bash_history.bak \ -- "$@") ) return 0 } complete -o default -F _re re rex
这段补齐配置的意思是说,让 skeleton_compgen_word.pl
这个脚本拿着re命令所
带的参数以换行符为分割符(-d '\n'),去 ~/.bash_history.bak
里找匹配,
找到以后先打个分号(-p \;),再把这个匹配行打出来。
以我想重新编译一下Android里我司自加的uboot为例,我只记得编译的命令是mm,
所以我就输入 re mm uboot .0
然后就按Tab键(也就是一般shell下的补齐
键),这样上面的 _re
函数就会被执行。
skeleton_compgen_word.pl
这个脚本有个特点,它看到最后一个参数如果是 .0
.1 .2
这种格式的话,它就会把第0个、第1个或第2个匹配项抽出来打印出去然
后马上退出(而不是默认的把所有匹配项都打出去)。由于我的历史命令文件是
动态调整的,最近用过的历史命令会出现在最前面,所以这里补出来的第0个应该
就是我想要的(否则我可以打.1去选择下一个,等等)。
下面就是魔术了:我的第一条匹配的历史命令(应该说是一个组合命令)是
(cd $(lookup-file vendor/marvell/generic/tcmd/kernel-helper); time mm
-j8 -k uboot)
,由于Tab键按下时最后一个参数是.0,所以.0会被补齐成这条
(跟它完全看不出有什么匹配关系的)历史命令,也就是说你会看到输入从 re
mm uboot .0
变成了这样:
re mm uboot (cd $(lookup-file vendor/marvell/generic/tcmd/kernel-helper); time mm -j8 -k uboot)
但是,人生最有意思的就是这个但是!眼睛亮的你肯定发现了问题,这个历史命 令被re给吃掉了!它成了re的参数,并且由于括号的存在,事实上是个语法错误! 怎么样才能让re“吃了我的给我吐出来”呢?前面说了,(-p \;)会在匹配的历史 命令之前先打个分号出来,所以你看到的是:
re mm uboot ;(cd $(lookup-file vendor/marvell/generic/tcmd/kernel-helper); time mm -j8 -k uboot)
分号和换行符是Bash里的语句分隔符,加了这个分号之后 re mm uboot ;
成为
一条独立的语句什么也不干的随风去了,剩下我们真正想要的好干活啊。
如果不加.0的话我们按Tab键是什么效果呢?这时候一般会有多个匹配项,Bash会 把它们都列出来。如果是Bash自带的补齐机制,它会要求你继续输入能继续匹配 的子串。以apt-get install latex的补齐为例,Bash会提示有这么些选项:
latex209-base latex-cjk-chinese latex-cjk-korean latexila-data latex209-bin latex-cjk-chinese-arphic-bkai00mp latex-cjk-thai latex-make latex209-src latex-cjk-chinese-arphic-bsmi00lp latex-cjk-xcjk latexmk latex2html latex-cjk-chinese-arphic-gbsn00lp latexdiff latex-mk latex2rtf latex-cjk-chinese-arphic-gkai00mp latexdraw latexml latex2rtf-doc latex-cjk-common latex-fonts-sipa-arundina latex-sanskrit latex-beamer latex-cjk-japanese latex-fonts-thai-tlwg latex-xcolor latex-cjk-all latex-cjk-japanese-wadalab latexila
所以你要继续输入-cjk(假设你想要装的是 latex-cjk-chinese-arphic-gkai00mp ),然后再按一下Tab键,Bash会提示你还 有这么些选项(它倒是会自动帮你添个减号把-cjk补成-cjk-):
$apt-get install latex-cjk- # 这里连按两次Tab键 latex-cjk-all latex-cjk-chinese-arphic-bsmi00lp latex-cjk-common latex-cjk-korean latex-cjk-chinese latex-cjk-chinese-arphic-gbsn00lp latex-cjk-japanese latex-cjk-thai latex-cjk-chinese-arphic-bkai00mp latex-cjk-chinese-arphic-gkai00mp latex-cjk-japanese-wadalab latex-cjk-xcjk
然后你输入ch,bash会自动帮你补成chinese,但接下来又提示你:
$apt-get install latex-cjk-chinese latex-cjk-chinese latex-cjk-chinese-arphic-bsmi00lp latex-cjk-chinese-arphic-gkai00mp latex-cjk-chinese-arphic-bkai00mp latex-cjk-chinese-arphic-gbsn00lp
然后你输入-a,bash会自动帮你补成-arphic-,但接下来又提示你:
$apt-get install latex-cjk-chinese-arphic- latex-cjk-chinese-arphic-bkai00mp latex-cjk-chinese-arphic-bsmi00lp latex-cjk-chinese-arphic-gbsn00lp latex-cjk-chinese-arphic-gkai00mp
好了,我想你肯定明白我的意思了。
按照我的补齐方法,apt-get install latex之后按两下Tab键,应该出现这样的提示:
$apt-get install latex 00: latex209-base 11: latex-cjk-chinese-arphic-gbsn00lp 01: latex209-bin 12: latex-cjk-chinese-arphic-gkai00mp 02: latex209-src 13: latex-cjk-common 03: latex2html 14: latex-cjk-japanese 04: latex2rtf 15: latex-cjk-japanese-wadalab 05: latex2rtf-doc 16: latex-cjk-korean 06: latex-beamer 17: latex-cjk-thai 07: latex-cjk-all 18: latex-cjk-xcjk 08: latex-cjk-chinese 19: latexdiff 09: latex-cjk-chinese-arphic-bkai00mp 31 total zzz... please use hil (history list)! 10: latex-cjk-chinese-arphic-bsmi00lp
然后我加个.12再按个Tab就得到我想要的啦吼吼吼!
(刚刚为这个Demo写了一个临时的补齐配置:
function _apt_get() { local cur prev local IFS=$'\n' COMPREPLY=() shift COMPREPLY=( $(skeleton_compgen_word.pl \ "latex209-base latex209-bin latex209-src latex2html latex2rtf latex2rtf-doc latex-beamer latex-cjk-all latex-cjk-chinese latex-cjk-chinese-arphic-bkai00mp latex-cjk-chinese-arphic-bsmi00lp latex-cjk-chinese-arphic-gbsn00lp latex-cjk-chinese-arphic-gkai00mp latex-cjk-common latex-cjk-japanese latex-cjk-japanese-wadalab latex-cjk-korean latex-cjk-thai latex-cjk-xcjk latexdiff latexdraw latex-fonts-sipa-arundina latex-fonts-thai-tlwg latexila latexila-data latex-make latexmk latex-mk latexml latex-sanskrit latex-xcolor" \ -- "${COMP_WORDS[$COMP_CWORD]}") ) return 0 } complete -o default -F _apt_get apt-get
)
所有的脚本都可以在 system-config 中找到,见我的系统配置。
Footnotes:
Emacs下我写的类似的补齐方式见skeleton-complete(中文)和 skeleton-complete(英文)。