文件名模式或目录的 bash 补全

Rob*_*b I 13 bash tab-completion bash-scripting

我正在尝试设置 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
Run Code Online (Sandbox Code Playgroud)

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

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

Den*_*nis 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
Run Code Online (Sandbox Code Playgroud)

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