【问题标题】:Nested bash autocompletion script嵌套 bash 自动完成脚本
【发布时间】:2012-03-09 13:10:37
【问题描述】:

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

谢谢!

【问题讨论】:

    标签: bash bash-completion


    【解决方案1】:

    对于第一级可能的子命令,我有点不清楚。 是否可以输入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)
        ...
    

    【讨论】:

      猜你喜欢
      • 2014-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-23
      • 2014-05-20
      • 2012-09-20
      • 2013-02-06
      • 1970-01-01
      相关资源
      最近更新 更多