linux shell中的命令自动补全(compgen complete)与 命令行参数解析

很多时候,当我们写一个脚本时,我们总会提供一些可选的命令选项。当可选项比较多的时候,比如git, 如果能够提供命令自动补全,无疑是锦上添花的事。而且个人认为,这种方式,比采用将命令做成选择菜单要更好一些。


假设我们现在这样一个脚本,脚本执行命令时bsu,  类似git,脚本有两个一级主命令pushbaseline, createrepo,然后这两个一级主命令下还有若干选项

pushbaseline  --qcom  --mtk  --name=(NX01, NX02)     #要求  --qcom --mtk不能同时出现,- -name=xxx可以与前面任意一个选项同时出现

createrepo   --git  --repo  --name=xxx  --auth=(W, R, RW) # 同上,这里--git, --repo不能同时出现。 后面两个选项随意

正式行动之前我们做一个简单的需求分析,正所谓不做需求分析就干活,“加班没日夜, 累死也枉然大笑

以pushbaseline为例,这里要求--qcom --mtk不能同时出现,如果直接在脚本中实现,就要判断之前输入中有没有输入--qcom,如果有输入,就不能再把--mtk作为命令自动补全的候选者。这种逻辑很复杂,对shell脚本不熟的人,只能望洋兴叹——“呵呵”。

事实上,从实际情况来看的话,为什么不能同时出现,因为它们都属于某个属相的描述,所以这里简单的改为--platfrom=(qcom, mtk),问题就巧妙解决了。


下面开始写脚本,上面将--qcom --mtk 改编为--platform=(qcom,mtk),缺少了简单选项,为此再额外加一个 --multi

自动补全,linux提供了两个重要命令 compgen, complete

命令:compgen -W "aa ab bb cc" -- “a”   

表示从"aa ab bb cc"  匹配出以“a”开头的单词

这条命令的返回结果就是 “aa ab”。 


命令:complete -F  __cmd_HUB  bsu

表示当执行bsu命令时,自动补全的候选单词由函数__cmd_HUB计算得到,具体的承载容器是变量COMPREPLY

特别说明一下,像这样的complete -F XXX   ./test.sh  也是合法的。如果XXX的计算后得到COMPREPLY=(aa bb cc), 则输入 ./test.sh 之后, 按tab键,可以自动弹出候选选项aa bb cc。


解释的话说的有点多,下面直奔主题了

[plain] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. function __cmd_HUB() {  
  2.         #$COMP_CWORD是系统自动变量,表示当前命令单词索引。 0表示第一个单词,也就是bsu。  
  3.     case $COMP_CWORD in  
  4.     0)  #仍在完成根命令,这里不需要处理  
  5.         ;;  
  6.     1)  #根命令已经完成,这里开始补充一级主命令  
  7.         #${COMP_WORDS[0]}是根命令,在这个例子中就是bsu   
  8.         eval __cmd_${COMP_WORDS[0]}  
  9.         ;;  
  10.     2|*)#一级主命令已经完成,这里开始补充一级主命令的选项  
  11.         #${COMP_WORDS[1]}是一级主命令,在这个例子中就是pushbaseline或者createrepo  
  12.         eval __cmd_${COMP_WORDS[1]}  
  13.         ;;  
  14.     esac  
  15. }  
  16.   
  17. complete -F __cmd_HUB bsu  

如果有同学对eval命令不了解,就找度娘吧。

上面我们做了一个约定,要获取命令<command>的选项,则总是调用函数__cmd_<command>获得,因此下面就要实现__cmd_bsu, __cmd_pushbaseline, __cmd_createrepo

[plain] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. function __cmd_bsu() {  
  2.     local cur="${COMP_WORDS[COMP_CWORD]}"  
  3.     local options="$MAIN_COMMAND"  
  4.     COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )  
  5. }  

[plain] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. function __cmd_pushbaseline() {  
  2.     local cur="${COMP_WORDS[COMP_CWORD]}"  
  3.     COMPREPLY=()  
  4.     case $cur in  
  5.     --name=*)  
  6.         local options="NX01 NX02"  
  7.         COMPREPLY=( $(compgen -W "${options}" -- ${cur#--name=}) )  
  8.         ;;  
  9.     --platform=*)  
  10.         local options="qcom mtk"  
  11.         COMPREPLY=( $(compgen -W "${options}" -- ${cur#--platform=}) )  
  12.         ;;  
  13.     *)   
  14.         local options="--platform= --name= --multi"  
  15.         COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )  
  16.         ;;  
  17.     esac      
  18. }  


命令自动补全都到此为止,篇幅有点长了,下面长话短说,直接处理命令,以命令 bsu  pushbaseline --platform=qcom   --name=NX01 --multi 为例

在bsu函数中完成命令转发,在各个子命令中详细解析参数

[plain] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. function bsu() {  
  2.     case $1 in  
  3.     pushbaseline)  
  4.         shift  
  5.         __parsing_pushbaseline $@  
  6.         ;;  
  7.     createrepo)  
  8.         shift  
  9.         __parsing_createrepo $@  
  10.         ;;  
  11.     *)  
  12.         echo "unknown command $1"  
  13.         ;;  
  14.     esac      
  15. }  
  16.   
  17. function __parsing_pushbaseline() {  
  18.     while [ $# -gt 0 ]; do  
  19.     case $1 in  
  20.     --platform=*)  
  21.         local platform=${1#--platform=}  
  22.         ;;  
  23.     --name=*)  
  24.         local name=${1#--name=}  
  25.         ;;  
  26.     --multi)  
  27.         local multi=1  
  28.         ;;  
  29.     esac  
  30.       
  31.     shift     
  32.     done  
  33.       
  34.     bsu_pushbaseline $platform $name $multi  
  35. }  
  36.   
  37. function bsu_pushbaseline()  
  38. {  
  39.     echo bsu_pushbaseline $@  
  40. }  

解析命令的关键一点,对于--xxx=YY的选项,可以使用模式匹配运算符快速得到想要的选项。这里简单起见,没有将代码做很多的形式化,有需要的话,只要利用eval函数,相信难不倒各位看官。


over,happy new year to everyone!

猜你喜欢

转载自blog.csdn.net/huohongpeng/article/details/79052010