1

我一直在尝试将 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 函数,但目前我不知道该怎么做。如果您对如何实现这一点也有建议,我将不胜感激。

谢谢!

4

1 回答 1

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)
    ...
于 2012-02-21T00:24:16.723 回答