我正在尝试设置 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
我认为这个简单的解决方案有效,因为它:
- 匹配以以下结尾的目录和文件
.txt
- 处理文件名中的空格
- 在文件夹补全末尾添加斜线,且没有尾随空格
- 在文件完成匹配的末尾添加空格
密钥正在传递-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