3

重现步骤

  • 在 tmp 上创建目录,在里面添加 1 个文件。

    mkdir /tmp/testdir && touch /tmp/testdir/examplefile
    
  • 粘贴下面的脚本/tmp/completion.sh

    # BEGIN AUTOCOMPLETE
    function _foo_complete() {
    local comnum cur opts
    [[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    opts="--help --restart -h -r"
    if (( COMP_CWORD > comnum )); then
     COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
     return
    fi
    if [[ ${cur} == -* ]]; then
     COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
     return 0
    else
     COMPREPLY=( $(for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done) )
    fi
    }
    complete -F _foo_complete foo.sh
    # END AUTOCOMPLETE
    
  • 那就采购吧。

    . /tmp/completion.sh
    

预期结果

$ foo.sh --restart examplefile <tab><tab>
examplefile           
$ foo.sh --restart examplefile <tab><tab>
examplefile        
$ foo.sh --restart examplefile <tab><tab>
examplefile     
$ foo.sh --restart examplefile <tab><tab>

相反会发生什么

$ foo.sh --restart examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile

我希望该建议显示为可能的完成,但实际上并未完成(出于显示目的)。以前有人问这个问题,但到目前为止还没有给出答案。

关于-o nosort

我研究了那个选项,它只在 Bash 4.4+ 上可用,我在我的 16.04 机器上试过,但它失败了。寻找更全球化的解决方案

4

3 回答 3

3

你可以试试这个技巧;根据您的操作系统,这可能对您有用:

注意:我将完成功能剥离为相关TabTab功能

#!/bin/bash
mkdir -p /tmp/testdir && touch /tmp/testdir/examplefile

_foo_complete() {
    local dirpath=/tmp/testdir
    local nullglob=$( shopt -q nullglob && echo true || echo false )

    $nullglob || shopt -s nullglob
    COMPREPLY=( "$dirpath"/* )
    $nullglob || shopt -u nullglob

    COMPREPLY=( "${COMPREPLY[@]#"$dirpath"/}" )

    [ ${#COMPREPLY[@]} -eq 1 ] && COMPREPLY+=( $'\xC2\xA0' )
}
complete -F _foo_complete foo.sh

后记:

这与@pynexj答案的想法基本相同:添加第二个不可见的元素到,从而在保留列表的同时COMPREPLY禁用 Tab自动完成。TabTab

现在的问题是 bash 会COMREPLY自动排序,因此 ASCIIspace字符在数字上是第一个printable字符,它将显示为列表的第一列。

为了解决这个问题,我尝试了 UTF-8 字符集中的几乎所有其他空白字符,它们都被排序到与 ASCIIspace字符相同的等级;除了 之外NON-BREAKING-SPACE,这就是我在这里使用的。

修复不是完全证明,因为有很多 UTF-8 字符会在它之后排序,最重要的是,它会根据操作系统得到不同的处理:一些sort实现将赋予它与 ASCIIspace字符相同的等级,而另一些实现惯于。想一想,什么是NON-BREAKING-SPACE概念?这是一个空白,但同时也像一个字母!

于 2022-01-06T23:11:12.223 回答
1

尝试以下compspec.sh(基于OP的代码):

function _foo_complete()
{
    local comnum cur opts

    [[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;

    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    opts="--help --restart -h -r"

    if (( COMP_CWORD > comnum )); then
        COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
        if [[ ${#COMPREPLY[@]} -gt 0 ]]; then
            #
            # you can try COMPREPLY+=( zzz ) and see what's happening
            #
            COMPREPLY+=( ' ' )
        fi
        return
    fi

    if [[ ${cur} == -* ]]; then
        COMPREPLY=( $( compgen -W "${opts}" -- ${cur} ) )
        return 0
    else
        COMPREPLY=( $( for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done ) )
    fi
}

complete -F _foo_complete foo.sh

在此处输入图像描述


更新:

是否可以将空字符串移动到完成的末尾,所以看起来没有空格?

如果您可以自己对完成候选进行排序,则可以使用complete -o nosort (需要 Bash 4.4+) 。

于 2022-01-01T11:43:55.643 回答
0

根据您的完整要求编辑的代码:

_test(){
   COMPREPLY=(                                                                                                                      
      $( [[ "$2" == -* ]] && compgen -W'-a -ab -c' -- "$2" \                                                                
      || [[ -d test ]] && compgen -W'$(basename -a test/*)' -- "$2" | grep -v -w -f <(printf "%s\n" "${COMP_WORDS[@    ]}:1:((COMP_CWORD-1))"))
   )
}

if the test directory doesn't exist completion would work with current directory contents so we have to check it

options can be used multiple times as you didn't specify it. 

1 2 完成 -F _test 测试

于 2022-01-04T21:51:38.193 回答