bash完成文件名模式或目录


13

我正在尝试设置bash完成脚本并遇到一些麻烦。

我想进行设置,以使列出的补全是与特定扩展名匹配的文件或目录(可能包含该扩展名的文件,也可能不包含该扩展名的文件)。

我遇到的麻烦是,让我包含文件目录的-o plusdirs -f -X '!*.txt'补全的唯一方法是使用诸如之类的东西,但是当我让bash完成其中一个目录时,它只是在末尾添加了一个空格,而不是削减。

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}

  #COMPREPLY=( $( compgen -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -f -G '*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o filenames -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o dirnames  -f -X '!*.txt' -- $cur ) )
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
  return 0
}

complete -F _xyz xyz

我也尝试了所有注释掉的行,但是它们甚至都没有扩展目录。

为了进行测试,我一直在一个包含一个.txt文件和一个目录“ dir”的目录中运行该文件(其中没有.txt文件,尽管这并不重要)。xyz <TAB>使用此功能键入将列出目录和.txt文件,但是键入xyz d<TAB>将扩展为xyz dir(好吧,在“ dir”之后有一个空格)。

Answers:


10

如果你看一下函数_cd()的/ etc / bash_completion,你会看到它追加尾随斜线本身和完整得到所谓的选项-o nospaceCD

您可以对xyz执行相同的操作,但必须分别验证找到的匹配项是目录(如果是,添加斜线)还是文件(如果是,请添加空格)。这应该在for循环中完成,以处理所有找到的匹配项。

另外,要正确处理包含空格的路径,必须将内部文件分隔符设置为仅换行符并转义空格。使用IFS=$'\n'与联合printf %q品牌完成工作,几乎所有的字符。1必须特别注意不要逃脱尾随空间。

以下应该工作:

_xyz ()
{
    local IFS=$'\n'
    local LASTCHAR=' '

    COMPREPLY=($(compgen -o plusdirs -f -X '!*.txt' \
        -- "${COMP_WORDS[COMP_CWORD]}"))

    if [ ${#COMPREPLY[@]} = 1 ]; then
        [ -d "$COMPREPLY" ] && LASTCHAR=/
        COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR")
    else
        for ((i=0; i < ${#COMPREPLY[@]}; i++)); do
            [ -d "${COMPREPLY[$i]}" ] && COMPREPLY[$i]=${COMPREPLY[$i]}/
        done
    fi

    return 0
}

complete -o nospace -F _xyz xyz

1换行符在这里是明显的例外,因为它是一个内部文件分隔符。


这很好用(尽管很糟糕,它不是内置的)。谢谢!
罗伯一世

1
有什么理由不使用“ $ 2”而不是“ $ {COMP_WORDS [COMP_CWORD]}”?
爱德华·福克

3

我认为这个简单的解决方案的工作原理是:

  1. 匹配以结尾的目录和文件 .txt
  2. 处理文件名中的空格
  3. 在文件夹补全的末尾添加斜杠,没有尾随空格
  4. 在文件完成匹配的末尾添加空间

关键过去了-o filenames。这已在RHEL 5.3的GNU bash 3.2.25和osx的GNU bash 4.3.18上进行了测试

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}

  local IFS=$'\n'
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
}

complete -o filenames -F _xyz xyz

是的,看起来确实很棒。简单得多,感谢您抓住重要的论点!
罗伯一世
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.