如何使用bash的complete或compgen -C(命令)选项?

如何使用bash的complete或compgen -C(命令)选项?

在 bash 中创建 shell 完成功能时,该-C选项似乎非常强大且常见。它的定义如下:

-C 命令

命令 在子 shell 环境中执行,其输出用作可能的完成。

这看起来真的很简单。但奇怪的是,事实并非如此。如果我做:

$ complete -C "echo one two three" test.sh

然后输入test.sh并点击一次 [tab],我得到该行填充

$ test.sh one two three test.sh  test.sh

后退。什么?!为了比较,

$ complete -W "one two three" test.sh

完全符合我的预期:它提供了,, 或者尽可能完成(当然,按排序顺序)。

我在任何地方都找不到任何好的文档,所以我正在尝试......也许分号有帮助?complete -C "echo one two three;" test.sh...啊,好吧,这有帮助一些test.sh,因为它消除了最后的奇怪之处。但它仍然填写完整的字符串one two three。这很奇怪,因为上面的描述肯定是说“可能的完成”,复数。 ...所以,嗯,啊,换行符?咱们试试吧complete -C "echo -e 'one\ntwo\nthree';" test.sh

好的,所以,这是有希望的。如果我打字test.sh [tab],我就会回来one three two。但随后,事情就出了问题。我添加一个o来解决歧义,所以,,test.sh o[tab]回报

o      one    three  two

这令人费解。事实上,我输入的任何字符串都会添加到列表中;如果我这样做test.sh wtf[tab],我就会得到one three two wtf回应。我想我可能需要用 做一些复杂的事情compgen,但是,我再次强调,这与预期的一样-W。而且,事实上

$ complete -W '$(echo one two three)' test.sh

工作得很好(注意单引号以防止过早扩展/执行,以防您执行比echo可能产生可变结果更复杂的操作)。

我在这里缺少什么?

答案1

该命令的工作是-C确定要插入哪些文本来响应完成请求。界面有点奇怪:

  • 的参数-C被解释为 bash 脚本片段。 Bash 将三个正确引用的字符串附加到此片段中:

    • 其参数正在完成的命令;
    • 光标所在单词的前缀,一直到光标;
    • 光标之前的单词。
  • 一些变量被添加到环境中:

    • COMP_LINE包含执行完成的完整行。
    • COMP_POINT里面包含光标位置COMP_LINE(从0开始计数)。
    • COMP_TYPE正常完成时为 9,列出不明确完成时的替代项时为 33,菜单完成时为 37,在不明确完成之间切换时为 63,在部分完成后列出完成时为 64。
    • COMP_KEY包含触发完成的键(例如,如果用户按下 ,则为制表符Tab)。
  • 命令的输出被解释为用于替换当前单词的文本。请注意,这是替换,而不是附加的后缀;该命令应该按给定的前缀进行过滤。它可能包含多行,在这种情况下,每行都被视为可能的替换。

这与所提供的机制大致相同,并且更好有记录的,对于具有 的函数-F。函数得到了一个更理智的界面:它们可以读取当前命令的单词列表COMP_WORDS变量,以及当前单词的起始位置COMP_CWORD;他们将结果写在COMPREPLY大批。

由于有用的参数(特别是要完成的前缀)在命令末尾传递,因此-C几乎只能与外部命令一起使用。当然你可以使用类似的东西sh -c …,但它不会很漂亮。

complete -C 'sh -c '\'for x in one two three; do case $x in "$1"*) echo "$x";; esac''\'

答案2

如果您希望将完成功能集中在complete定义内,而无需外部脚本和函数的麻烦,那么使用该complete -C选项的最简单方法是仅在命令字符串内定义处理程序函数。内置complete函数在执行命令字符串之后直接添加三个字符串,如下所示@Gilles“所以-别再邪恶了”他在回答中指出:

  1. 其参数正在完成的命令;
  2. 光标所在单词的前缀,一直到光标;
  3. 光标之前的单词。

对于原始问题的示例代码,我们只需要位置参数$2,以具有作为前缀的grep可能完成。$2要走的路是:

    complete -C 'makelist() { echo one; echo two; echo three; }; filter() { makelist | grep "^$2" | sort -u; }; filter' test.sh

输入 时test.sh t<tab>complete将执行带有空格的命令字符串,并在最后一个 后面附加“test.sh”、“t”和“test.sh” filter。该命令将:

  • 定义makelist函数
  • 定义filter函数
  • filter使用附加字符串作为参数 调用函数
    • filter将会通知makelist
    • makelist返回所有可能完成的列表
    • grep与光标所在单词的前缀匹配的补全,直至光标
    • 独特的是sort这些
    • 将它们传递回complete

相关内容