anl*_*lar 17 bash autocomplete
我想为逗号分隔的参数列表创建完成规则。例如,我有接收服务器名称列表的命令:
myscript -s name1,name2,name3
Run Code Online (Sandbox Code Playgroud)
此时我已经设法编写了以下完成:
_myscript () {
local cur prev opts
_get_comp_words_by_ref cur prev
opts='-s'
servers='name1 name2 name3'
if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
else
case "${prev}" in
-s)
if [[ "$cur" == *,* ]]; then
local realcur prefix
realcur=${cur##*,}
prefix=${cur%,*}
COMPREPLY=( $(compgen -W "${servers}" -P "${prefix}," -- ${realcur}) )
else
COMPREPLY=( $(compgen -W "${servers}" -- ${cur}) )
fi
;;
*)
# do nothing
;;
esac
fi
}
Run Code Online (Sandbox Code Playgroud)
但它至少有两个问题:
这种情况下的最佳做法是什么?也许 bash-completions 有一些 csv-lists 的捆绑功能?
基本上没有办法解决你描述的问题,因为 bashCOMPREPLY
直接在显示中使用值,然后替换用户的文本 - 而要得到你想要的,你需要首先生成可能的完成(只是额外的服务器名称,不带前缀)以便 bash 显示,然后当 bash 即将用最长的非冲突字符串替换用户文本时,您需要它再次调用您的脚本以生成带有前缀的文本 - 和 bash没有设施。
我能想到的最好的方法COMPREPLY
是生成只有第一个单词具有整个前缀 ( COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) )
),这样如果只有一个可能的完成,它会自动正确完成,而如果有多个可能的完成,那么 bash 将不会删除到目前为止输入的内容(因为 in 的第一个单词COMPREPLY
具有完整的前缀,因此与当前输入的文本匹配,并且将被 bash 选中以替换用户的文本)并且将显示不带前缀的选项 - 除了对于已经包含前缀的单词,因此输出将如下所示:
$ command -s banana,a
ananas apricot banana,apple
Run Code Online (Sandbox Code Playgroud)
“apple”在完成选项中排在最后,因为它带有以“b”开头的前缀 - 非常混乱。所以我不建议这样做。
关于重复项 - 为了不显示重复项,您只需要打破$prefix
它的部分(简单IFS="," prefix_parts=($prefix)
:)然后迭代它们并且只留下$servers
尚未列出的名称。打字很乏味,所以我不会在这里展示它,但相对来说比较琐碎,所以我相信你可以做到:-)。
总而言之,我认为您不应该对输入选项使用逗号分隔值,至少如果您希望 bash 帮助您完成。
您可以支持这样的选项格式:command -s <server> [<server> [..]]
然后为了完成-s
选项之后的条目以外的条目,只需扫描$COMP_WORDS
数组,$COMP_CWORD
直到找到一个选项(匹配的字符串-*
),如果它是“-s”,则您需要完成服务器名称完成。