如何编写bash自动补全脚本(2)

除了这里使用的-W参数之外,command命令还有许多其他参数。大部分参数都以固定的方式生成补全列表,这意味着我们无法动态干预过滤它们的输出结果。

例如,如果我们想将当前目录下的子目录名作为dothis应用程序的补全列表,可以将complete命令做如下修改:

complete -A directory dothis

此时,在dothis命令之后敲tab键,我们可以获取当前目录下子目录的列表:

$ dothis <tab><tab> dir1/ dir2/ dir3/

更多关于complete命令的参数参见。

动态补全

本小节中,我们将实现带有以下逻辑的dothis可执行程序的自动补全:

如果用户在命令后面直接按tab键,将显示用户执行历史中的最近50个命令。

如果用户在输入一个能够从执行历史中匹配到多个命令的数字后按tab键,将显示这些命令以及它们的序号。

如果用户在输入一个从执行历史中只能匹配到一个命令的数字后按tab键,将自动补全这个数字,而不显示命令内容(如果这个描述有些迷糊,看了后面的内容会能够有更好的理解,放心)。

让我们从定义一个每次dothis命令补全时都会调用的函数。将补全脚本改成这样:

#/usr/bin/env bash _dothis_completions() { COMPREPLY+=("now") COMPREPLY+=("tomorrow") COMPREPLY+=("never") } complete -F _dothis_completions dothis

对该脚本的一些说明:

我们使用complete命令的-F参数定义_dothis_completions函数为dothis命令提供补全功能。

COMPREPLY是一个存储补全列表的数组,自动补全机制使用该变量来显示补全内容。

现在让我们重新source下补全脚本,验证下补全功能:

$ dothis <tab><tab> never now tomorrow

完美,补全脚本能够输出和之前一样的补全词列表。等等,好像不是?再来试下:

$ dothis nev<tab><tab> never now tomorrow

我们可以看到,虽然我们在输入了nev字母后再触发了自动补全,显示的补全列表和之前的一样并没有做自动过滤,这是为什么呢?

COMPREPLY变量的内容总是会显示,补全函数需要自己处理其中的内容。

如果COMPREPLY变量中只有一个元素,那么这个词会自动补全到命令之后。由于目前的实现总是返回相同的三个词,不会触发这个功能。

使用compgen命令:它是一个用于生成补全列表的内置命令,支持complete命令的大部分参数(例如-W参数指定补全词列表,-d参数补全目录),并能够基于用户已经输入的内容进行过滤。

如果有些迷惑也不用着急,下面通过一些命令及其输出来展示它的使用:

$ compgen -W "now tomorrow never" now tomorrow never $ compgen -W "now tomorrow never" n now never $ compgen -W "now tomorrow never" t tomorrow

通过这些示例,我们已经可以使用该命令了,不过在此之前,还需要了解为获取dothis命令已经输入的内容。bash自动补全功能提供了相关以支撑这个自动补全。这里是一些比较重要的变量:

COMP_WORDS:当前命令行中已经输入的词数组。

COMP_CWORD:当前光标所处词位于COMP_WORDS数组中的索引值。既当按下tab键时光标所处词的索引。

COMP_LINE:当前命令行。

为了获取dothis命令后面的词,我们可以使用COMP_WORDS[1]的值。

再次修改自动补全脚本:

#/usr/bin/env bash _dothis_completions() { COMPREPLY=($(compgen -W "now tomorrow never" "${COMP_WORDS[1]}")) } complete -F _dothis_completions dothis

source该文件查看效果:

$ dothis never now tomorrow $ dothis n never now

现在,让我们抛开now、never、tomorrow这些词,从命令执行历史中抓取真实的数字。

fc -l命令后面增加一个负数-n可以显示最近执行过的n条命令。因此我们将会使用:

fc -l -50

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/7abde8daf5e5ef373eea3856d785025d.html