可能な完了をどのように繰り返すのですか? [コピー]

可能な完了をどのように繰り返すのですか? [コピー]

与えられた部分命令に対して可能な完了範囲を得ることができるようにしたい。たとえば、一部のコマンドでは、service um次のような完成が可能です。

$ service um<TAB><TAB>
umountfs      umountnfs.sh  umountroot

completions次の動作を持つ関数が必要です。

$ for x in $(completions 'service um'); do
> echo $x
> done
umountfs
umountnfs.sh
umountroot

進捗状況の一部:これまでに学んだこと

私はこれが完全な答えになることができる1つのアプローチだと思います。私は間違いなく完全な答えを見たいのですが、<TAB><TAB>プログラムではなく同じ機能を提供する比較的簡単なアプローチを考えると、より柔軟な解決策があるかもしれません。

serviceこのコマンドの完了メカニズムは_service次の関数であることがわかります。

$ complete -p service
complete -F _service service

このコンプリート関数が呼び出されると、_service複数の環境変数が設定されます(例COMP_{LINE,POINT,KEY,TYPE,WORDS,CWORD}:;を参照)。バッシュのマニュアルページ)、この関数は完成したコマンド、完成した単語、前の単語を引数として取り、COMPREPLY可能な完成を埋めます。したがって、私が望む機能はcompletions次のように定義できます。

function completions() {
    # Produce an array of tokens in the input.
    read -a words <<< $1

    # Use "complete -p ${words[0]}" to determine how the 
    # completions are computed. This could be complicated
    # if complete is given flags other than -F.
    completion_func=???

    # Set all those COMP_* environment variables appropriately.

    # Run the function to populate COMPREPLY. This version
    # assumes words has length at least 2, but that can be
    # fixed.
    $completion_func ${words[0]} ${words[-1]} ${words[-2]}

    echo ${COMPREPLY[@]}
}

相対的な複雑さに加えて、<TAB><TAB>このアプローチの欠点は環境を変えることです。

ベストアンサー1

ここに出発点として使用できると考えられる基本機能があります。さまざまな方法で失敗する可能性があります。ここで他の誰かがこれを改善できることを願っています。

completions () (
    if [ -f /usr/share/bash-completion/bash_completion ]; then
        . /usr/share/bash-completion/bash_completion
    elif [ -f /etc/bash_completion ]; then
        . /etc/bash_completion
    fi

    IFS="$COMP_WORDBREAKS" read -a words <<<"$1"
    complete_setting=($(complete -p "${words[0]}"))
    complete_optstring=":abcdefgjksuvprDEo:A:G:W:F:C:X:P:S:"
    while getopts "$complete_optstring" option "${complete_setting[@]:1}"
    do
        case $option in
            F) complete_functon="$OPTARG"
                ;;
            *) # Run around screaming!                    
                ;;
        esac
    done
    COMP_WORDS=("${words[@]}")
    COMP_LINE="$1"
    COMP_POINT="${#COMP_LINE}"
    COMP_CWORD=$((${#COMP_WORDS[@]} - 1))
    "$complete_functon" 
    printf "%s\n" "${COMPREPLY[@]}"
)

メモ:

  • 対話型シェルで関数として使用する場合、初期ソースは必要ありません。
  • complete検索語 Split を使用するので for に設定しましたCOMP_WORDBREAKSIFSread
  • complete -p再利用可能な方法で現在の完了設定を印刷すると、元の方法でオプションを解析できます。
  • ()この関数は(代わりに)サブシェルを使用するため、{}現在の環境が邪魔にならないようにしてください。

おすすめ記事