Conclusão de bash para valores separados por vírgula

16

Gostaria de criar uma regra de conclusão para a lista de parâmetros separados por vírgula. Por exemplo. Eu tenho o comando que recebe lista de nomes de servidores:

myscript -s name1,name2,name3

Neste momento, consegui escrever após a conclusão:

_myscript () {
  local cur prev opts

  _get_comp_words_by_ref cur prev

  opts='-s'

  servers='name1 name2 name3'

  if [[ ${cur} == -* ]] ; then
    COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
  else
    case "${prev}" in
      -s)
        if [[ "$cur" == *,* ]]; then
          local realcur prefix
          realcur=${cur##*,}
          prefix=${cur%,*}
          COMPREPLY=( $(compgen -W "${servers}" -P "${prefix}," -- ${realcur}) )
        else
          COMPREPLY=( $(compgen -W "${servers}" -- ${cur}) )
        fi
        ;;
      *)
        # do nothing
        ;;
    esac
  fi
}

Mas tem pelo menos dois problemas:

  1. As sugestões para o valor atual incluem todos os valores anteriores em seu prefixo.
  2. Não considera valores duplicados.

Quais são as melhores práticas para esses casos? Talvez o bash-completion tenha algumas funções empacotadas para listas csv?

    
por diffycat 13.04.2014 / 14:46

1 resposta

6

Basicamente, não há como consertar os problemas que você descreve, porque o bash usa os valores em COMPREPLY diretamente no display e substitui o texto do usuário - enquanto para obter o que você quer, você precisa primeiro gerar o Conclusões possíveis (apenas os nomes de servidor adicionais, sem o prefixo) para o bash exibir, quando o bash estiver prestes a substituir o texto do usuário pela string não conflitante mais longa, você precisará chamar seu script novamente para gerar o texto com o prefixo - e o bash não tem facilidade para isso.

O melhor que eu consegui fazer é ter o COMPREPLY gerado apenas com a primeira palavra com o prefixo inteiro ( COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) ) ), de modo que, se houver apenas uma conclusão possível, ela seja concluída automaticamente corretamente, enquanto se houver mais de uma conclusão possível, o bash não removerá o que foi digitado até agora (porque a primeira palavra em COMPREPLY tem o prefixo inteiro e, portanto, corresponde ao texto digitado no momento e será selecionada pelo bash para substituir o usuário texto) e exibirá as opções sem o prefixo - exceto para aquela palavra que já contém o prefixo, então a saída ficará assim:

$ command -s banana,a
ananas     apricot    banana,apple

"apple", como classificado por último nas opções de conclusão, porque carrega o prefixo que começa com "b" - muito confuso. Então eu não recomendo fazer isso.

Em relação aos duplicados - para não mostrar duplicatas, você só precisa dividir $prefix em sua parte (fácil: IFS="," prefix_parts=($prefix) ) e, em seguida, iterar sobre eles e deixar em $servers os nomes que ainda não foram listado. É tedioso digitar, então não mostrarei aqui, mas é relativamente trivial, então tenho certeza que você pode gerenciar: -).

Para resumir, não acho que você deva usar valores separados por vírgulas para opções de entrada, pelo menos se você espera que o bash o ajude na conclusão.

Você pode oferecer suporte a um formato de opções como este: command -s <server> [<server> [..]] e, em seguida, para a conclusão de entradas diferentes da imediatamente após a opção -s , basta verificar novamente a matriz $COMP_WORDS de $COMP_CWORD até encontrar uma opção (string que corresponde a -* ) e se for "-s", você precisa fazer a conclusão do nome do servidor.

    
por 05.07.2014 / 00:07