嵌套bash自动完成脚本

时间:2012-02-18 09:23:24

标签: bash bash-completion

我一直在尝试将bash完成支持添加到我最近使用过的命令行程序中,但似乎我已经碰壁了。

以下是我想要自动完成的命令和子命令

  • 主要命令为foo,应对子命令versionprocesshelp执行自动完成。进一步的自动完成取决于子命令。

    • 如果用户在主命令后输入-,则自动完成会对这些字词执行完成:--activate--deactivate

    • 如果用户输入--deactivate,则应执行bash命令输出的自动完成(让我们说ls)。

  • version:未执行自动完成功能
  • process:自动填充默认为列出目录(包括当前和父级)

    • 如果用户输入-,则自动完成会对这些字词执行完成:--color--verbose然后停止
  • 如果用户输入help,则自动完成功能适用于其他子命令(processversion)。

这是我当前实施的自动完成脚本(失败严重):

_foo() {
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    words=("${COMP_WORDS[@]}")
    cword=$COMP_WORD
    opts="process version help"

    case "$prev" in
    -*)
        local subopts="--activate --deactivate"
            COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
            case "$cur" in
                --deactivate)
                    COMPREPLY=( $(ls) )
                ;;
            esac
         ;;
    version)
        COMPREPLY=()
        ;;
    process)
        case "$cur" in
            -*)
                local subopts="--color --verbose"
                COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
                ;;
            *)
                COMPREPLY=( $(compgen -A directory))
                ;;
        esac
        ;;
    help)
        COMPREPLY=( $(compgen -W "process version" -- ${cur}) )
        ;;
   esac
   } 
 complete -F _foo foo

你可能会发现Bash也不是我的主要优势。我正在考虑为每个子命令编写单独的bash函数,但我现在还不知道该怎么做。如果您对如何实现这一点有任何建议,我将非常感激。

谢谢!

1 个答案:

答案 0 :(得分:3)

如果第一级可能的子命令对我来说有点不清楚。 是否可以输入foo --activatefoo - --activate?后者看起来有些奇怪,但更适合您给定的代码。 第一个听起来更合理,但意味着将--activate等作为一种全局参数,与你的子命令一样在同一级别上进行处理。

然而,当你还没有输入任何东西时,你错过了默认值。 请尝试以下代码:

_foo() {
    local cur prev opts

    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    words=("${COMP_WORDS[@]}")
    cword=$COMP_CWORD
    opts="process version help"

    case "$prev" in
    -*)
        local subopts="--activate --deactivate"
        COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
        case "$cur" in
            --deactivate)
                COMPREPLY=( $(ls) )
            ;;
        esac
        return 0
         ;;
    version)
        COMPREPLY=()
        return 0
        ;;
    process)
        case "$cur" in
            -*)
                local subopts="--color --verbose"
                COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
                ;;
            *)
                COMPREPLY=( $(compgen -A directory))
                ;;
        esac
        return 0
        ;;
    help)
        COMPREPLY=( $(compgen -W "process version" -- ${cur}) )
        return 0
        ;;
   esac
   COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
   return 0
} 
complete -F _foo foo

与你的基本相同但是: 在底部,将COMPREPLY设置为您的第一级子命令,以便它们完成。 如果输入了子命令,则应返回(0)以不到达最终语句。

给出的示例将与foo - --activate一起使用,这可能不是您想要的。 因此,如果您想输入foo --activate,请将相应的行更改为

    case "$prev" in
    --activate)
        COMPREPLY=()
        return 0
        ;;
    --deactivate)
        COMPREPLY=( $(compgen -W "$(ls)" -- ${cur}) )
        return 0
        ;;
    version)
    ...