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 に答える