这是以下讨论的后续问题:
https://bugs.launchpad.net/ubuntu/+source/bash-completion/+bug/1394920
假设我有一个文件夹~/tmp
,其中包含一些文件和目录:
$ mkdir a; touch file1.txt; mkdir a/b; mkdir a/c; touch a/d; mkdir a/b/c
我现在尝试创建一个完成脚本来完成~/tmp
中的文件名,但complete -o filenames
选项仅在当前目录为~/tmp
时才能正常工作。
有关更多背景信息,请参阅上面的链接。这是我得到的:
$ cat setup
_compTest() {
local cur baseFolder
cur="${COMP_WORDS[$COMP_CWORD]}"
baseFolder=~/tmp
compopt -o nospace
COMPREPLY=( $(
cd "$baseFolder"
if [[ ${cur: -1} != "/" && -d $cur ]] ; then
echo "$cur/"
else
compgen -f "$cur"
fi
) )
}
complete -F _compTest aaa
然后我来源:
$ . setup
然后我就可以了
$ aaa <tab><tab>
问题1:在完成列表中的目录名称末尾没有添加斜杠(这样可以轻松地将目录与完成列表中的文件名分开)
问题2:对于aaa a/<tab><tab>
,完成列表为a/b a/c a/d
,但a/
前缀不应该在那里。它应该是b/ c/ d
。
答案 0 :(得分:6)
我会把这个函数写成:
_compTest ()
{
local cur; local tmp; local tmp_escaped; local i;
_get_comp_words_by_ref cur;
local _compreply=()
tmp=~/tmp/
tmp_escaped=${tmp//\//\\\/}
cur=$tmp$cur;
if [ "$1" == "-d" ]; then
_cd
else
_filedir;
fi;
for i in "${COMPREPLY[@]}"; do
[ -d "$i" ] && [ "$i" != "$tmp." ] && [ "$i" != "$tmp.." ] && i="$i/"
_compreply=("${_compreply[@]}" "$i")
done
COMPREPLY=(${_compreply[@]/$tmp_escaped/})
} && complete -o nospace -F _compTest aaa_files
_compTestDir()
{
_compTest -d
} && complete -o nospace -F _compTestDir aaa_directories
它有3个部分,
$cur
添加基本目录前缀 - 〜/ tmp。_filedir
~/tmp
COMPREPLY
醇>
仅供记录:您可以使用此逻辑来完成相对于路径的许多其他类型的文件名,例如
//...
。 http://localhost/*
目录的public_html
路径。答案 1 :(得分:1)
将添加为评论,但我没有声誉...
以@anishsane的answer为基础,如果只有一个完成选项而不是目录,那么您可能不要包含nospace
选项。例如,程序可能会在您当前完成的参数之后接受另一个参数。如果只有一个选项,我们应该接受该选项,然后转到下一个参数。
为此,请从nospace
行中删除complete
并添加逻辑以仅在需要时启用nospace
:
# [...]
# Do not include trailing space in results if there is more than one option
# or if the only option is a directory
[ "${#_compreply[@]}" -gt 1 ] && compopt -o nospace
[ "${#_compreply[@]}" -eq 1 ] && [ -d "${_compreply[0]}" ] && compopt -o nospace
COMPREPLY=(${_compreply[@]/$tmp_escaped/})
} && complete -F _compTest aaa_files