bash - 制表符完成时如何防止 bash 完成替换字符

标签 bash bash-completion

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

使用 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                                                                                                                       

但现在 Tab 补全看起来至少可以说很奇怪:

@/usr/bin      @/usr/games

有没有显示正常的文件选项卡完成(没有“@”前缀)但在点击选项卡时保留“@”?

最佳答案

所以,这引起了我的兴趣,所以我一直在通读 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

现在,我承认 split if箱子有点脏,肯定有更好的方法,但我需要更多咖啡因。

此外,不管它对你有什么值(value),我还发现了 -P <prefix> compgen 的参数,这将防止您不得不遍历 $COMPREPLY[*]}调用后的数组 compgen , 像这样

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

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

关于bash - 制表符完成时如何防止 bash 完成替换字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10493505/

相关文章:

git - bash/git 中分支和文件完成之间的冲突

bash - 传递变量来查找命令-exec

linux - 删除包含指定单词的所有行

linux - 如何使用另一个文件中已经存在的完成来扩展 bash-completion?

bash - 带有 * 的意外 bash 目录列表

Bash 补全 - 如何摆脱不需要的 Tab 键?

vim - 是否可以在 VIM 中为 :! 或 :r ! 启用 bash_completion?

java - 一个 liner 重命名一组文件和目录

linux - 无法覆盖到文件

linux - 将 bash 脚本移植到任何可以在 Windows 上运行的东西