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

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

我正在尝试设置 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”后面有一个空格)。

答案1

如果你看_cd()一下/etc/bash_completion,你会看到它附加了尾部斜杠本身,并且完全的-o nospace被调用时可以选择光盘

你也可以对坐标,但必须单独验证找到的匹配项是目录(如果是,则添加斜线)还是文件(如果是,则添加空格)。这应该在 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换行符在这里显然是例外,因为它是一个内部文件分隔符。

答案2

我认为这个简单的解决方案有效,因为它:

  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

相关内容