8.8 可编程完成的例子

评论 0 浏览 0 2023-01-26

completecompgen提供的默认动作之外,获得额外完成功能的最常见的方法是使用一个shell函数,并使用complete -F将其绑定到一个特定的命令上。

下面的函数为cd内置函数提供了补全功能。 它是一个合理的例子,说明shell函数在用于补全时必须做什么。这个函数使用作为$2传递的单词来确定要完成的目录名。你也可以使用COMP_WORDS数组变量;当前单词由COMP_CWORD变量索引。

这个函数依靠completecompgen内置函数来完成大部分工作,只增加了Bash cd在接受基本目录名之外的事情:波浪号扩展(见2 波浪号扩展),搜索$CDPATH中的目录,这在上面有描述(见4.1 Bourne Shell内置程序),以及对cdable_vars shell选项的基本支持(见2 Shopt 内置程序)。_comp_cd修改了IFS的值,使其只包含一个换行,以适应包含空格和制表符的文件名 –compgen将其生成的可能的补语每行打印一次。

可能的完成度进入COMPREPLY数组变量,每个数组元素一个完成度。当函数返回时,可编程的完成度系统从那里检索完成度。

# A completion function for the cd builtin
# based on the cd completion function from the bash_completion package
_comp_cd()
{
    local IFS=$' \t\n'    # normalize IFS
    local cur _skipdot _cdpath
    local i j k

    # Tilde expansion, which also expands tilde to full pathname
    case "$2" in
    \~*)    eval cur="$2" ;;
    *)      cur=$2 ;;
    esac

    # no cdpath or absolute pathname -- straight directory completion
    if [[ -z "${CDPATH:-}" ]] || [[ "$cur" == @(./*|../*|/*) ]]; then
        # compgen prints paths one per line; could also use while loop
        IFS=$'\n'
        COMPREPLY=( $(compgen -d -- "$cur") )
        IFS=$' \t\n'
    # CDPATH+directories in the current directory if not in CDPATH
    else
        IFS=$'\n'
        _skipdot=false
        # preprocess CDPATH to convert null directory names to .
        _cdpath=${CDPATH/#:/.:}
        _cdpath=${_cdpath//::/:.:}
        _cdpath=${_cdpath/%:/:.}
        for i in ${_cdpath//:/$'\n'}; do
            if [[ $i -ef . ]]; then _skipdot=true; fi
            k="${#COMPREPLY[@]}"
            for j in $( compgen -d -- "$i/$cur" ); do
                COMPREPLY[k++]=${j#$i/}        # cut off directory
            done
        done
        $_skipdot || COMPREPLY+=( $(compgen -d -- "$cur") )
        IFS=$' \t\n'
    fi

    # variable names if appropriate shell option set and no completions
    if shopt -q cdable_vars && [[ ${#COMPREPLY[@]} -eq 0 ]]; then
        COMPREPLY=( $(compgen -v -- "$cur") )
    fi

    return 0
}

我们使用-F选项向complete安装完成功能。

# Tell readline to quote appropriate and append slashes to directories;
# use the bash default completion for other arguments
complete -o filenames -o nospace -o bashdefault -F _comp_cd cd

由于我们希望Bash和Readline为我们处理一些其他的细节,我们使用了其他几个选项来告诉Bash和Readline该怎么做。-o filenames选项告诉Readline,可能的补语应该被视为文件名,并被适当引用。该选项还将导致Readline对它能确定为目录的文件名附加一个斜线(这就是为什么我们可能想要扩展_comp_cd来附加一个斜线,如果我们使用通过CDPATH找到的目录。-o nospace 选项告诉Readline不要在目录名上附加一个空格字符,以防我们想附加进去。 -o bashdefault 选项带来了其余的"Bash default" completions – Bash添加到默认Readline集的可能的完成方式。这些包括诸如命令名补全、以‘$’或‘${’开头的变量补全、包含路径名扩展模式的补全(参见8 文件名扩展),等等。

一旦使用complete安装,每当我们试图为cd命令完成单词时,_comp_cd就会被调用。

还有更多的例子–大部分常见的GNU、Unix和Linux命令的补全集合–可作为bash_completion项目的一部分。许多GNU/Linux发行版都默认安装了这个项目。该项目最初由Ian Macdonald编写,现在在https://github.com/scop/bash-completion/。还有用于其他系统的端口,如Solaris和Mac OS X。

bash_completion包的旧版本与bash一起发布在examples/complete子目录下。

最后更新2023-03-15
0 个评论
当前页面书签