【问题标题】:custom bash completion with whitespace and paths带有空格和路径的自定义 bash 完成
【发布时间】:2014-11-27 03:54:31
【问题描述】:

我不知道我做错了什么。我的 bash_completion 文件设置如下:

_bcd()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=( $(compgen -W "$(back_directory.pl --complete $cur)" -- $cur) )
}
complete -o filenames -o nospace -F _bcd bcd

back_directory.pl 是一个程序,它将返回树上的目录路径:back_directory.pl --complete Th 产生:This\ test/ 但是:

22:50:24-Josh@Joshuas-MacBook-Air:~/Desktop/bcd/This test/more    white/t$ bcd Th<TAB><TAB>
This   test/

如上所示,它不会自动完成包含空格的目录(但它会显示完成选项)。

应该是这样的:bcd This\ test/

我认为-o filenames 应该添加反斜杠来转义空格。感谢您的帮助:)

【问题讨论】:

  • back_directory.pl 是否返回多个路径?如果是这样,它如何分隔值?
  • @rici 如果可能的话,它将返回多个路径——由空格分隔。但我认为在这种情况下它没有任何区别
  • 如果以空格分隔,则不能包含空格。空白是空白。你怎么能分辨出来?但是,如果您使用其他分隔符,您可以在本地设置 IFS 以让 compgen 使用它。 (IFS=: compgen ...)
  • 呵呵……我的错。这样可行!它只是搞砸了格式,以便完成选项从命令行开始。例如。 bcd &lt;tab&gt;'Desktop/ &lt;NEWLINE&gt; Josh/ ... 由于某种原因还添加了单引号
  • 您是否正在使用包含换行符的路径进行测试?还是 perl 脚本输出换行符(以及)来分隔路径?

标签: linux bash unix completion


【解决方案1】:

您对compgen 的单次调用会产生一个单词(包含嵌入的换行符),因此您只需向COMPREPLY 添加一个可能的补全。相反,您需要一次处理一项back_directory.pl 的输出。每个项目都作为可能的匹配项进行测试,如果compgen 返回一个非空字符串,则将其添加到COMPREPLY

_bcd() {
    local cur=${COMP_WORDS[COMP_CWORD]}
    IFS=: read -a matches < <(back_directory.pl --complete "$cur")
    for match in "${matches[@]}"; do
        possible=$(IFS= compgen -W "$match" -- "$cur")
        [[ $possible ] && COMPREPLY+=( "$possible" )
    done
}

(注意:我假设back_directory.pl 将产生类似于

的单行输出
directory1:directory two:directory three:directory4

)

【讨论】:

  • 感谢您的反馈。不幸的是,这与我之前遇到的问题相同。如果我使用complete -o filenames -o nospace -F _bcd bcd,我会得到带有空格的目录的补全,但以“/”开头的补全会被搞砸并产生:arqt/ joshua/ qko/ scripts/ tor/ users//complete -o nospace -F _bcd bcd 不适用于包含空格的目录,但会产生(正确):/arqt/ /joshua/ /qko/ /scripts/ /tor/ /users/
  • 呃。好吧,我用这条线让它工作得很好:possible=$(IFS= compgen -W "$match" -- "${cur#/}")。但是,这会将bcd /us&lt;TAB&gt; 重写为bcd users/。我想我可以忍受这个,但有点奇怪:/ 如果有什么我可以做的,请告诉我
  • 好吧...这似乎工作:if [[ ${#COMPREPLY[@]} -eq 1 &amp;&amp; "$cur" =~ ^/ ]]; then COMPREPLY=( "/${COMPREPLY[0]}" ); fi 我要摆弄它,看看它是否正常工作:)
  • 现在似乎工作得很好!有点 hacky,但是嘿——它有效!
  • 当然,当匹配是 tortos 时,它会自动完成 tto,这会中断...
【解决方案2】:

为了完整起见,这是最终文件:

_bcd()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    IFS=: read -a matches < <(back_directory.pl --complete "$cur")
    for match in "${matches[@]}"; do
        possible=$(IFS= compgen -W "$match" -- "${cur#/}")
        [[ $possible ]] && COMPREPLY+=( "$possible" )
    done

    longest=""
    for e in "${COMPREPLY[@]}"; do
        if [[ "$longest" == "" ]]; then
            longest="$e"
        fi
        while [[ ! "$e" =~ ^$longest ]]; do
            longest=${longest%?}
        done
    done

    if [[ $longest != "$input" && "$cur" =~ ^/ ]]; then
        for ((i=0; i<${#COMPREPLY[@]}; i++))
        do
            COMPREPLY[$i]="/${COMPREPLY[$i]}"
        done
    fi
}
complete -o filenames -o nospace -F _bcd bcd

脚本back_directory.pl --complete 将返回由冒号分隔的单行路径。

我的解决方案似乎很糟糕,但它确实有效。

基本上,它会从当前单词中删除一个开头的斜杠,创建所有匹配项(不包含开头的斜杠),然后检查$longest 是否与$input 不同,这意味着 bash 会将您当前的单词更改为一些不同的东西——在这种情况下,我们添加一个开始的斜线。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    • 2015-06-09
    • 2012-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多