如何防止在标签完成时替换字符完成bash完成

时间:2012-05-08 06:16:19

标签: bash bash-completion

我正在为一个工具构建一个bash完成脚本,该脚本与curl共享文件上传语义。

使用curl,你可以这样做:

curl -F var = @ file

上传文件。

我的应用程序具有类似的语义,我希望能够在按下'@'后显示可能的文件。不幸的是,这证明是困难的:

cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
if [[ "$cur" == @* && "$prev" == '=' ]]; then
    COMPREPLY=( $(compgen -f ${cur:1}) )
    return 0
fi 

因此,如果命令(到目前为止)以:

结尾
abc=@

当前目录中的文件将显示。

 var=@/usr/                                                                                                                       
 /usr/bin      /usr/games 

问题是如果我真的按Tab键完成,'@'就会消失!

 var=/usr/bin

所以看起来bash用标签式COMPREPLY替换整个当前单词。

避免这种情况的唯一方法就是这样做:

        COMPREPLY=( $(compgen -f ${cur:1}) )
        for (( i=0; i<${#COMPREPLY[@]}; i++ )); 
        do 
            COMPREPLY[$i]='@'${COMPREPLY[$i]} 
        done                                                                                                                       

但是现在标签的完成看起来很奇怪:

@/usr/bin      @/usr/games

有没有显示正常的文件标签完成(没有'@'前缀)但是在点击标签时保留'@'?

2 个答案:

答案 0 :(得分:5)

所以,这引起了我的兴趣,所以我一直在阅读bash完成源(可在/ etc / bash_completion中找到)。

我遇到了这个变量:${COMP_WORDBREAKS},它似乎可以控制用于分隔单词的字符。

我还发现了这个函数,_get_cword和补充_get_pword,两者都建议分别代替${COMP_WORDS[COMP_CWORD]}${COMP_WORDS[COMP_CWORD-1]}

所以,把所有这些放在一起,我做了一些测试,这就是我想出来的:这似乎对我有用,至少,希望它也适合你:

# maintain the old value, so that we only affect ourselves with this
OLD_COMP_WORDBREAKS=${COMP_WORDBREAKS}
COMP_WORDBREAKS="${COMP_WORDBREAKS}@"

cur="$(_get_cword)"
prev="$(_get_pword)"

if [[ "$cur" == '=@' ]]; then
    COMPREPLY=( $(compgen -f ${cur:2}) )

    # restore the old value
    COMP_WORDBREAKS=${OLD_COMP_WORDBREAKS}
    return 0
fi

if [[ "$prev" == '=@' ]]; then
    COMPREPLY=( $(compgen -f ${cur}) )

    # restore the old value
    COMP_WORDBREAKS=${OLD_COMP_WORDBREAKS}
    return 0

fi

现在,我承认分裂if的情况有点脏,绝对有更好的方法,但我需要更多的咖啡因。

此外,无论对你有什么价值,我还发现-P <prefix> compgen参数$COMPREPLY[*]},这会阻止你在调用{compgen数组后循环{1}},就像这样

COMPREPLY=( $(compgen -P @ -f ${cur:1}) )

但是,面对完整的解决方案,这有点多余。

答案 1 :(得分:0)

试试这个......

function test
{
  COMPREPLY=()
  local cur="${COMP_WORDS[COMP_CWORD]}"
  local opts="Whatever sort of tabbing options you want to have!"
  COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
}
complete -F "test" -o "default" "test"
# complete -F "test" -o "nospace" "sd" ## Use this if you do not want a space after the completed word