Como posso passar por cima de conclusões possíveis? [duplicado]

17

Gostaria de poder colocar em minhas mãos uma matriz de conclusões possíveis para um determinado comando parcial. Por exemplo, o comando parcial service um tem as seguintes conclusões possíveis:

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

Gostaria de ter uma função completions com o seguinte comportamento:

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

Progresso parcial: o que aprendi até agora

Aqui está uma abordagem que eu acho que pode ser feita em uma resposta completa. Eu definitivamente gostaria de ver essa resposta completa, mas dado que o relativamente simples <TAB><TAB> fornece a mesma funcionalidade de uma maneira não programática, parece que também poderia haver uma solução mais flexível.

Eu posso descobrir que o mecanismo de conclusão do comando service é a função _service :

$ complete -p service
complete -F _service service

Quando esta função de conclusão _service é chamada, um conjunto de variáveis de ambiente é definido (a saber, COMP_{LINE,POINT,KEY,TYPE,WORDS,CWORD} ; consulte a página man bash ), a função é dada como argumentos o comando sendo completado, a palavra sendo completada, e a palavra anterior, e preenche COMPREPLY com as conclusões possíveis. Então, minha função completions desejada poderia ser definida assim:

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[@]}
}

Além da complexidade relativa em relação a <TAB><TAB> , uma desvantagem dessa abordagem é que ela altera o ambiente.

    
por Anton Geraschenko 05.02.2015 / 17:57

1 resposta

5

Aqui está uma função rudimentar que eu acho que pode servir como ponto de partida. Pode falhar de várias maneiras, esperamos que outras pessoas aqui possam melhorar:

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[@]}"
)

Notas:

  • Se você estiver usando isso como uma função para o seu shell interativo, a fonte inicial não é necessária.
  • complete procura palavras divididas usando COMP_WORDBREAKS , por isso, definimos IFS como read .
  • complete -p imprime a configuração de conclusão atual de forma reutilizável, para que possamos analisar as opções da maneira que o faria.
  • A função usa um subshell ( () em vez de {} ), portanto, seu ambiente atual não deve ser perturbado.
por 07.02.2015 / 11:00