命令行选项补全

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

 

posted on 2020-06-19 14:41  裸睡的猪  阅读(824)  评论(0编辑  收藏  举报