8.6 可编程完成

评论 0 浏览 0 2023-01-26

当尝试对命令的参数进行单词完成时,已经使用 complete 内置函数(见可编程补全内建程序)为其定义了完成规范(compspec),调用可编程完成工具。

首先,确定命令名称。 如果已经为该命令定义了compspec,则使用该compspec来生成该词的可能补全列表。 如果命令词是空字符串(在空行的开头尝试补全),则使用complete-E选项定义的任何compspec。 如果命令词是一个全路径名,则首先搜索该全路径名的compspec。如果没有找到全路径名的compspec,则会尝试为最后的斜线后面的部分寻找compspec。 如果这些搜索没有找到compspec,则使用complete-D选项定义的任何compspec作为默认值。 如果没有默认的compspec,Bash会尝试对命令词进行别名扩展,作为最后的手段,并尝试从任何成功的扩展中为命令词找到compspec

一旦找到了compspec,它就会被用来生成匹配的单词列表。 如果没有找到compspec,就会执行上面描述的默认的Bash补全(见Letting Readline Type For You)。

首先,使用compspec指定的动作。 只有以被完成的单词为前缀的匹配才会被返回。 当-f-d选项被用于文件名或目录名的完成时,shell变量FIGNORE被用来过滤匹配。 参见5.2 Bash 变量,以获得关于FIGNORE的描述。

接下来会生成任何由文件名扩展模式指定的-G选项的补全词。 由模式生成的词不需要与被补全的词相匹配。 GLOBIGNORE shell变量不用于过滤匹配词,但FIGNORE shell变量被使用。

接下来,将考虑指定为-W选项参数的字符串。 首先使用IFS特殊变量中的字符作为分隔符来分割该字符串。 在字符串中尊重壳引号,以便为包含shell元字符或IFS值中的字符提供一个机制。然后,每个词都要使用大括号扩展、波浪号扩展、参数和变量扩展、命令替换和算术扩展,如上所述(见3.5 Shell的扩展)。 结果使用上述规则进行分割(见7 分词)。 扩展的结果与被完成的词进行前缀匹配,匹配的词成为可能的完成。

在这些匹配产生后,任何用-F-C选项指定的shell函数或命令都会被调用。 当命令或函数被调用时,COMP_LINECOMP_POINTCOMP_KEYCOMP_TYPE变量被分配值,如上所述(见5.2 Bash 变量)。 如果一个shell函数被调用,COMP_WORDSCOMP_CWORD变量也被设置。当函数或命令被调用时,第一个参数($1)是参数被完成的命令的名称,第二个参数($2)是被完成的词,第三个参数($3)是当前命令行中被完成的词前面的词。 没有对生成的完成词进行过滤,函数或命令可以完全自由地生成匹配。

首先调用用-F 指定的任何函数。该函数可以使用任何 shell 工具,包括下面描述的compgencompopt 内置函数(见可编程完成内建程序),来生成匹配。 它必须把可能的完成度放在COMPREPLY数组变量中,每个数组元素一个。

接下来,任何用-C选项指定的命令都会在相当于命令替换的环境下被调用。 它应该打印出一个完成的列表,每行一个,到标准输出。 如果有必要,反斜杠可以用来转义换行。

在所有可能的补全被生成之后,任何用-X选项指定的过滤器被应用到列表中。 过滤器是一个用于路径名扩展的模式;模式中的‘&’被替换为被补全的单词的文本。 字面的‘&’可以用反斜杠转义;反斜杠在尝试匹配之前被删除。任何与模式相匹配的完成语都将从列表中删除。 一个领先的‘!’否定了模式;在这种情况下,任何与模式不匹配的完成语都将被删除。 如果nocasematch shell选项(见2 Shopt 内置程序中关于shopt的描述)被启用,匹配将不考虑字母字符的大小写。

最后,任何用-P-S选项指定的前缀和后缀都被添加到完成度列表的每个成员中,结果作为可能的完成度列表返回给Readline完成码。

如果先前应用的操作没有产生任何匹配,并且在定义compspec时向complete提供了-o dirnames选项,则会尝试完成目录名。

如果在定义compspec时向complete提供了-o plusdirs选项,则会尝试完成目录名称,并将任何匹配结果加入到其他操作的结果中。

默认情况下,如果找到了一个编译器,无论它产生了什么,都会作为全部可能的完成方式返回给完成代码。 默认的Bash完成方式不会被尝试,而且Readline默认的文件名完成方式被禁用。如果在定义编译器时,-o bashdefault选项被提供给了complete,那么如果编译器没有产生匹配,就会尝试默认的Bash补全。 如果在定义编译器时,-o default选项被提供给了complete,如果编译器(以及如果尝试,默认的Bash补全)没有产生匹配,就会执行Readline’的默认补全。

当compspec指出需要目录名称补全时,可编程的补全功能强制Readline在补全的名称上附加一个斜线,这些名称是目录的符号链接,受制于mark-directories Readline变量的值,而不管mark-symlinked-directories Readline变量的设置。

有一些对动态修改完成度的支持。这在与-D指定的默认完成结合使用时最为有用。作为完成处理程序执行的shell函数有可能通过返回124的退出状态来表明完成应该被重试。如果一个shell函数返回124,并且改变了与正在尝试完成的命令相关的compspec(在函数执行时作为第一个参数提供),可编程完成就会从头开始,尝试为该命令找到一个新的compspec。这允许在尝试完成的过程中动态地建立一套完成方法,而不是一次性地加载。

例如,假设有一个编译器库,每个编译器都保存在一个与命令名称相对应的文件中,下面的默认完成函数将动态加载完成度。

_completion_loader()
{
    . "/etc/bash_completion.d/$1.sh" >/dev/null 2>&1 && return 124
}
complete -D -F _completion_loader -o bashdefault -o default
最后更新2023-03-12
0 个评论
当前页面书签