Bash 康普根没有';不能正确填写包含冒号的单词

Bash 康普根没有';不能正确填写包含冒号的单词,bash,tab-completion,bash-completion,compgen,Bash,Tab Completion,Bash Completion,Compgen,我在创建Bash完成函数时遇到了一个问题,因为命令应该包含冒号。键入命令并按tab键时,Bash会将命令行的内容插入到数组中,只有这些数组用冒号分隔。因此,命令: 假福:苹果 将成为: ('dummy'foo':'apple') 我知道一个解决方案是更改COMP_分词,但这不是一个选项,因为这是一个团队环境,在这个环境中,我可能会通过使用COMP_分词来破坏其他代码 然后建议使用\u get\u comp\u words\u by\u ref和\u ltrim\u colon\u complet

我在创建Bash完成函数时遇到了一个问题,因为命令应该包含冒号。键入命令并按tab键时,Bash会将命令行的内容插入到数组中,只有这些数组用冒号分隔。因此,命令:

假福:苹果

将成为: ('dummy'foo':'apple')

我知道一个解决方案是更改COMP_分词,但这不是一个选项,因为这是一个团队环境,在这个环境中,我可能会通过使用COMP_分词来破坏其他代码

然后建议使用
\u get\u comp\u words\u by\u ref
\u ltrim\u colon\u completions
变量,但从答案中我还不清楚如何使用这些变量

所以我在下面尝试了不同的解决方案。基本上,以字符串形式读取命令行,并通过计算“偏移量”来确定用户光标当前正在选择哪个单词。如果命令行中有一个冒号,其左边或右边有文本,它将在偏移量中各加1,然后从
COMP\u CWORD
变量中减去该值

  1 #!/bin/bash
  2 _comp() {
  3     #set -xv
  4     local a=("${COMP_WORDS[@]}")
  5     local index=`expr $COMP_CWORD`
  6     local c_line="$COMP_LINE"
  7                                                                             
  8     # Work out the offset to change the cursor by
  9     # This is needed to compensate for colon completions
 10     # Because COMP_WORDS splits words containing colons
 11     # E.g. 'foo:bar' becomes 'foo' ':' 'bar'.
 12     
 13     # First delete anything in the command to the right of the cursor
 14     # We only need from the cursor backwards to work out the offset.
 15     for ((i = ${#a[@]}-1 ; i > $index ; i--));
 16     do
 17         regex="*([[:space:]])"${a[$i]}"*([[:space:]])"
 18         c_line="${c_line%$regex}"
 19     done
 20     
 21     # Count instances of text adjacent to colons, add that to offset.
 22     # E.g. for foo:bar:baz, offset is 4 (bar is counted twice.)
 23     # Explanation: foo:bar:baz foo
 24     #              0  12  34   5   <-- Standard Bash behaviour
 25     #              0           1   <-- Desired Bash behaviour
 26     # To create the desired behaviour we subtract offset from cursor index.
 27     left=$( echo $c_line | grep -o "[[:alnum:]]:" | wc -l )
 28     right=$( echo $c_line | grep -o ":[[:alnum:]]" | wc -l )
 29     offset=`expr $left + $right`
 30     index=`expr $COMP_CWORD - $offset`
 31     
 32     # We use COMP_LINE (not COMP_WORDS) to get an array of space-separated
 33     # words in the command because it will treat foo:bar as one string.
 34     local comp_words=($COMP_LINE)
 35     
 36     # If current word is a space, add an empty element to array
 37     if [ "${COMP_WORDS[$COMP_CWORD]}" == "" ]; then
 38         comp_words=("${comp_words[@]:0:$index}" "" "${comp_words[@]:$index}"    )   
 39     fi
 40         
 41     
 42     local cur=${comp_words[$index]}
 43     
 44     local arr=(foo:apple foo:banana foo:mango pineapple)
 45     COMPREPLY=()
 46     COMPREPLY=($(compgen -W "${arr[*]}" -- $cur))
 47     #set +xv
 48 }   
 49 
 50 complete -F _comp dummy 
然后它将显示三个可用选项,
foo:apple-foo:banana-foo:mango
。到现在为止,一直都还不错。但如果我输入:

dummy foo:<TAB>
然后它将返回三个匹配结果:

foo:apple
foo:banana
foo:mango
因此,我假设Bash completion看到它有一个空字符串和三个可供完成的候选项,因此在命令行末尾添加前缀
foo:
,即使
foo:
已经是要完成的游标

我不明白的是如何解决这个问题。当不涉及冒号时,这很好——“松树”将始终完整到菠萝。如果我去更改阵列以添加更多选项:

local arr=(foo:apple foo:banana foo:mango pineapple pinecone pinetree)
COMPREPLY=()
COMPREPLY=($(compgen -W "${arr[*]}" -- $cur))
然后,当我键入
虚拟松树
时,它仍然愉快地显示出我的
菠萝松果松树
,并且没有试图在末尾添加多余的
松树


对于这种行为有什么解决方法吗?

每个候选选项中有多少冒号?bash的完成支持很混乱。bash完成项目包含了一些很好的技巧,可以满足像您这样的需求。我建议您花一些时间理解相关的帮助函数并重用它们。就我自己而言,我宁愿将字符串自动完成为
foo.apple foo.banana
,然后再将
转换为
。另一个选项是在shell中键入时引用字符串,像
dummy'foo
。每个候选选项中可能有多个冒号,或者没有。不幸的是,通过替换
而不是
或转义命令来更改命令行为将不是一个选项,因为我编写的不是我的程序。每个候选选项中有多少冒号?bash的完成支持非常混乱。bash完成项目包含了一些很好的技巧,可以满足像您这样的需求。我建议您花一些时间理解相关的帮助函数并重用它们。就我自己而言,我宁愿将字符串自动完成为
foo.apple foo.banana
,然后再将
转换为
。另一个选项是在shell中键入时引用字符串,像
dummy'foo
。每个候选选项中可能有多个冒号,或者没有。不幸的是,通过替换
而不是
或转义命令来更改命令行为不是一个选项,因为我编写的不是我的程序。
compgen -W 'foo:apple foo:banana foo:mango pineapple' -- foo:
foo:apple
foo:banana
foo:mango
local arr=(foo:apple foo:banana foo:mango pineapple pinecone pinetree)
COMPREPLY=()
COMPREPLY=($(compgen -W "${arr[*]}" -- $cur))