命令行选项补全
1、compgen
compgen(筛选命令)
这个命令,用来筛选生成 匹配单词的 候选补全结果。
-W wordlist |
分割 wordlist 中的单词,生成候选补全列表 |
[root@localhost ~]#compgen -W 'word1 word2 test' word1 word2 test [root@localhost ~]#compgen -W 'word1 word2 test' word word1 word2 [root@localhost ~]#
要列出所有可用的命令,只需键入以下命令 compgen -c 要列出可用的所有bash shell别名,请输入: compgen -a 显示所有bash内置插件,内建命令 compgen -b 显示所有bash关键字 compgen -k 显示所有bash函数 compgen -A function compgen -W "aa ab bb cc" -- "a" 表示从”aa ab bb cc” 匹配出以“a”开头的单词 这条命令的返回结果就是 “aa ab”。
2、complete
complete补全命令
-F function |
执行shell 函数,函数中生成COMPREPLY作为候选的补全结果 |
-C command |
将 command 命令的执行结果作为候选的补全 结果 |
-Gpattern |
将匹配 pattern的文件名作为候选的补全结果 |
-W wordlist |
分割 wordlist 中的单词,作为候选的补全结果 |
-p [name] |
列出当前所有的补全命令 |
-r [name] |
删除某个补全命令 |
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 自动补全是Bash自带的一个强大的功能,允许通过编码指定命令参数如何补全。
通常,补全脚本会放在/etc/bash_completion.d/ 目录下,方便统一启用所有补全脚本。 这里例子的命令为 foo [root@localhost bash_completion.d]#cat foo.sh #!/bin/bash _foo() { local cur=${COMP_WORDS[COMP_CWORD]} COMPREPLY=( $(compgen -W "exec help test" -- $cur) ) } complete -F _foo foo 如下,测试foo命令是否自动补全 [root@localhost ]# chmod +x /etc/bash_completion.d/foo.bash [root@localhost ]# source /etc/bash_completion.d/foo.bash [root@localhost ]# foo [Tab][Tab] exec help test 以上,source是为了这个foo.bash在当前会话生效。默认情况下,这个补全脚本不会被执行到,也就是说,补全命令未激活。
需要source激活这个脚本,就可以没有顾虑地使用了。 为了避免每次都要source一次,可以在bashrc加上这个命令。 bashrc全局配置在不同 linux 发行版可能位置不同,如下: Centos /etc/bashrc Ubuntu /etc/bash.bashrc (如果只在当前帐号生效,只要配置 ~/.bashrc 即可) 在bashrc文件末尾加上 source /etc/bash_completion.d/foo.bash,这样,每次登录到linux后,就会激活这个补全脚本。
# complete -W 'word1 word2 word3 test' foo # foo w<Tab> # foo word<Tab> # complete -p complete -W 'word1 word2 word3 test' foo complete -o filenames -F __udisks udisks # complete -r foo # complete -p complete -o filenames -F __udisks udisks
complete命令指定如何对各个名称进行补全。如果指定了选项“-p”或者没有指定任何选项,则把已有的补全方法用一种可以重新作为作为输入的格式打印出来。
选项“-r”用以删除指定名称的补全方法,不指定名称时删除所有的名称的补全方法。
选项“-D”的意思是其后的选项和动作将应用到默认命令补全,也就是说之前未定义的补全命令也可以补全。
选项“-E”的意思是其后的选项和动作将应用到空命令补全,也就是说补全空白行。
对于选项“-G”、“-W”、“-X”、“-P”和“-S”,应该使用括号进行保护,防止补全开始前被扩展。 “-o bashdefault”:如果没有生成补全条目,就使用bash默认的其它补全。 “-o default”:如果没有生成补全条目,就使用“readline”默认的文件名补全。 “-o dirnames”:如果没有生成补全条目,就进行目录名补全。 “-o filenames”:告诉“readline”生成文件名,以便进行与文件名相关的处理,
例如在目录名后面加上斜杠,引用特殊字符,去掉行尾的空格,目的是用于shell函数。 “-o noquote”:告诉“readline”不引用文件名,默认会进行引用。 “-o nospace”:告诉“readline”在补全的名称后不添加空格,默认添加空格。 “-o plusdirs”:生成补全条目之后,还会进行目录名补全并把结果添加到其它动作得到的结果中。 “-A alias”:别名,同选项“-a”。 “-A arrayvar”:数组变量名。 “-A binding”:“readline”键绑定名。 “-A builtin”:shell内建命令名,同选项“-b”。 “-A command”:命令名,同选项“-c”。 “-A directory”:目录名,同选项“-d”。 “-A disabled”:不可用的shell内建命令名。 “-A enabled”:可用的shell内建命令名。 “-A export”:导出的shell变量名,同选项“-e”。 “-A file”:文件名,同选项“-f”。 “-A function”:shell函数名。 “-A group”:组名,同选项“-g”。 “-A helptopic”:内建命令help支持的帮助主题。 “-A hostname”:主机名,从shell环境变量HOSTFILE中获取。 “-A job”:作业名,同选项“-j”。 “-A keyword”:shell保留字,同选项“-k”。 “-A running”:正在运行的作业名。 “-A service”:服务名,同选项“-s”。 “-A setopt”:内建命令set的选项“-o”可用的参数。 “-A shopt”:内建命令shopt可接受的选项名。 “-A signal”:信号名。 “-A stopped”:暂停的作业名。 “-A user”:用户名,同选项“-u”。 “-A variable”:所有的shell变量名,同选项“-v”。 “-C command”:在子shell中执行命令,并把其结果作为补全条目。 “-F function”:在当前的shell环境中执行函数function,执行时,
参数“$1”表示那个参数正在进行补全的命令名,参数“$2”表示补全的名称,
参数“$3”表示补全的名称前面的单词,表示结束执行时,从数组变量COMPREPLY中获取补全条目。 “-G globpat”:使用文件名扩展模式globpat进行扩展以生成可能的补全条目。 “-P prefix”:在所有的选项应用到补全结果后,在结果前添加前缀prefix。 “-S suffix”:在所有的选项应用到补全结果后,在结果后添加后缀suffix。 “-W wordlist”:使用特殊变量IFS中的字符拆分单词列表wordlist,并扩展拆分后的每个单词,结果中与待补全单词 匹配的条目就是补全条目。 “-X filterpat”:filterpat是进行文件名扩展时使用的模式,它作用于通过前面的选项和参数生成的补全列表,
并把每个与过滤模式匹配的条目删除,模式中前导的叹号表示否定,这时会删除与过滤模式不匹配的条目。
3、compopt
compopt(修改补全命令设置) 这个命令可以修改补全命令设置,注意了,这个命令必须在补全函数中使用,否则会报错。 # help compopt compopt: compopt [-o|+o option] [-DE] [name ...] 重点说明: +o option 启用 option 配置 -o option 弃用 option 配置 例如,设置命令补全后不要多加空格,方法如下: compopt -o nospace
4、内置补全变量
除了上面三个命令外,Bash还有几个内置变量来辅助补全功能,如下:
COMP_WORDS |
类型为数组,存放当前命令行中输入的所有单词 |
COMP_CWORD |
类型为整数,当前输入的单词在COMP_WORDS中的索引 |
COMPREPLY |
类型为数组,候选的补全结果 |
COMP_WORDBREAKS |
类型为字符串,表示单词之间的分隔符 |
COMP_LINE |
类型为字符串,表示当前的命令行输入字符 |
COMP_POINT |
类型为整数,表示光标在当前命令行的哪个位置 |
总结:
1. 查看已有的命令行补全 在启用可编程的命令行补全功能后,就已经有了一些定义好的命令补全功能。complete 命令用于定义命令行补全。 要查看已有的命令行补全,如下使用 complete 命令: complete -p | less 上面例子中的 -p 选项是可选的。
2. 定义一个命令名补全 通过 -c 选项可以将所有的可用命令作为一个命令的补全参数。在下面的例子里面,为 which 命令定义了一个补全
(LCTT译注:在按两下 TAB 时,可以列出所有命令名作为可补全的参数)。 $ complete -c which $ which [TAB][TAB] Display all 2116 possibilities? (y or n) 如上,如果按下 ‘y’,就会列出所有的命令名。
3. 定义一个目录补全 通过选项 -d,可以定义一个仅包含目录名的补全参数。在下面的例子中,为 ls 命令定义了补全。 $ ls countfiles.sh dir1/ dir2/ dir3/ $ complete -d ls $ ls [TAB][TAB] dir1/ dir2/ dir3/ 如上,连按下 TAB 仅会显示目录名。
4. 定义一个后台任务名补全 补全功能也能够以任务名作为补全参数。选项 -j 可以定义任务名作为传递给命令的参数,如下: $ jobs [1]- Stopped cat [2]+ Stopped sed 'p' $ complete -j ./list_job_attrib.sh $ ./list_job_attrib.sh [TAB][TAB] cat sed 关于后台任务,你可以参考 Linux 后台任务中的例子了解如何管理后台任务。
5. 通过 IFS 变量分割字符串得到补全值 可以通过 -W 选项定义补全值列表,然后通过 IFS 环境变量进行切分。切分结果会展开变量并作为补全显示。 $ export IFS=" " $ complete -W "bubble quick" ./sort_numbers.sh $ ./sort_numbers.sh [TAB][TAB] bubble quick 如上所述,字符串通过 IFS 分隔符进行切分后,内嵌的变量会被展开为变量值,所以可以如下使用变量: $ echo $SORT_TYPE1 bubble $ echo $SORT_TYPE2 quick $ complete -W "$SORT_TYPE1 $SORT_TYPE2" ./sort_numbers.sh $ ./sort_numbers.sh [TAB][TAB] bubble quick
6. 写个函数来生成补全 你可以引入一个函数来定义补全。使用 -F 选项将函数名传给 complete 命令,执行函数生成补全内容。例如,函数如下: _parser_options() { local curr_arg; curr_arg=${COMP_WORDS[COMP_CWORD]} COMPREPLY=( $(compgen -W '-i --incoming -o --outgoing -m --missed' -- $curr_arg ) ); } 在上述函数中: COMPREPLY : 该数组控制连按下 TAB 后显示的结果 COMP_WORDS : 该数组包含命令行输入的单词 COMP_CWORD : COMP_WORDS 数组的索引,使用它来区分命令行可以访问的单词位置 compgen : -W 基于 $current_arg 提供可能的补全及其参数 该函数放在 parser_option 文件中,并通过 source 命令引入: $ source parser_option 将该函数和你的 parser.pl 脚本关联起来: $ complete -F _parser_options ./parser.pl $ ./parser.pl [TAB][TAB] -i --incoming -o --outgoing -m --missed 如上,parser.pl 的选项是由函数 _parser_options() 生成的。 提示: 查看/etc/bash_completion 来了解更多的可编程补全函数。
7. 当第一个规则没有生成结果时,就使用第二个 如果定义的补全规则没有生成匹配时,可以使用 -o 选项生成补全。 $ complete -F _count_files -o dirnames ./countfiles.sh 如上,为 ./countfiles.sh 定义了 _count_files 补全函数。 如果 the _count_files() 函数没有生成任何匹配的话,就会触发目录补全。 $ ls countfiles.sh dir1/ dir2/ dir3/ $./countfiles.sh [TAB][TAB] dir1 dir2 dir3
8. #compgen最常用的选项是-W,通过-W参数指定空格分隔的单词列表。
h即我们在命令行Command-line当前键入的单词,执行完后会输出候选的匹配列表,这里是以h开头的所有单词. $ compgen -W 'hi hello how world' h hi hello how
9. # 指定通过_test函数对test进行补全 $ function _test() > { > echo -e "\n" > declare -p COMP_WORDS > declare -p COMP_CWORD > declare -p COMP_LINE > declare -p COMP_WORDBREAKS > } $ complete -F _test test 再输入以下命令按补全: [root@localhost simon]#test a b c [tab][tab] declare -a COMP_WORDS='([0]="test" [1]="a" [2]="b" [3]="c" [4]="")' declare -- COMP_CWORD="4" declare -- COMP_LINE="test a b c " declare -- COMP_WORDBREAKS=" \"'><=;|&(:"
例子:
1、首先实现命令脚本
#!/bin/bash function Usage() { echo -e "**********************************************************************" echo -e "Usage:" echo -e "Options:" echo -e "-h,-H,\t\tShow help information." echo -e "**********************************************************************" echo } while getopts "hH?" arg do case $arg in h|H|?) Usage $Name exit 1 ;; esac done #脚本必须运行在root权限下 if [ `id -u` -ne 0 ]; then echo -e "This script must be run as root! \r\n" exit 1 fi case $1 in 'foo') case $2 in 'foo1'|'foo2'|'foo3') echo -e "This is $2! \r\n" ;; *) Usage $Name exit 1 ;; esac;; 'test') case $2 in 'test1'|'test2') echo -e "This is $2! \r\n" ;; *) Usage $Name exit 1 ;; esac;; *) Usage $Name exit 1 ;; esac exit 0
2、接着,实现命令补全脚本
#!/bin/bash _parser_options() { COMPREPLY=() local cur=${COMP_WORDS[COMP_CWORD]}; #获取最后一个选项 local cmd=${COMP_WORDS[COMP_CWORD-1]}; #获取最后第二个选项 if [ ${COMP_CWORD} -eq 1 ]; then COMPREPLY=( $(compgen -W 'foo test' -- $cur) ); elif [ ${COMP_CWORD} -eq 2 ]; then case $cmd in 'foo') COMPREPLY=( $(compgen -W 'foo1 foo2 foo3' -- $cur) ) compopt -o nospace #是将补全后自动加的空格删掉 ;; 'test') COMPREPLY=( $(compgen -W 'test1 test2' -- $cur) ) ;; compopt -o nospace #是将补全后自动加的空格删掉 *) ;; esac fi } #complete -F _parser_options -o dirnames ramtest.sh complete -F _parser_options ramtest.sh
3、测试
[root@localhost simon]# cp parse.sh /etc/bash_completion.d/ [root@localhost simon]# source /etc/bash_completion.d/parse.sh [root@localhost simon]# cp ramtest.sh /bin/
[root@localhost simon]# ramtest.sh ********************************************************************** Usage: Options: -h,-H, Show help information. ********************************************************************** [root@localhost simon]# ramtest.sh [tab][tab] foo test [root@localhost simon]# ramtest.sh foo foo [tab][tab] foo1 foo2 foo3 [root@localhost simon]# ramtest.sh foo foo foo1 foo2 foo3 [root@localhost simon]# ramtest.sh foo foo1[tab][tab] foo1 [root@localhost simon]# ramtest.sh foo foo1