在 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“所以-别再邪恶了”他在回答中指出:
- 其参数正在完成的命令;
- 光标所在单词的前缀,一直到光标;
- 光标之前的单词。
对于原始问题的示例代码,我们只需要位置参数$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