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 um comando que recebe a lista de nomes de servidores:

myscript -s name1,name2,name3

Neste momento, consegui escrever a seguinte 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 2 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-completeions tenha algumas funções incluídas no csv-lists?

diffycat
fonte
3
O que pode ajudar é que você pode dividir valores separados por vírgula em uma lista iterável como esta: IFS=, LIST=("$VARIABLE")onde $ VARIABLE contém seus valores separados por vírgula.
Michael Ehrenreich
2
Boa ideia @MichaelEhrenreich, mas você não deve citar a frase $VARIABLE, caso contrário a quebra de palavras não acontece. apenas use IFS=, LIST=($VARIABLE).
Guss

Respostas:

6

Basicamente, não há como corrigir os problemas que você descreve, porque o bash usa os valores COMPREPLYdiretamente na tela e, em seguida, substitui o texto do usuário - enquanto, para obter o que deseja, você precisa primeiro gerar as possíveis conclusões (apenas as informações adicionais). nomes de servidor, sem o prefixo) para que o bash seja exibido; quando o bash estiver prestes a substituir o texto do usuário pela string mais longa e sem conflito, você precisará chamar o script novamente para gerar o texto com o prefixo - e bash não tem facilidade para isso.

O melhor que pude sugerir é que COMPREPLYseja gerado apenas a primeira palavra com o prefixo inteiro ( COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) )), para 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é o momento (porque a primeira palavra COMPREPLYtem o prefixo inteiro e, portanto, corresponde ao texto digitado no momento e será selecionado pelo bash para substituir o texto do usuário) e exibirá as opções sem o prefixo - exceto para aquela palavra que já contém o prefixo, a saída terá a seguinte aparência:

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

"apple", conforme classificado pela última vez nas opções de conclusão, pois contém o prefixo que começa com "b" - muito confuso. Então, eu não recomendo fazer isso.

Com relação às duplicatas - para não mostrar duplicatas, você só precisa dividir $prefixsua parte (easy IFS="," prefix_parts=($prefix):) e iterar sobre elas e deixar apenas $serversos nomes que ainda não estão listados. É tedioso digitar, então não vou mostrá-lo 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írgula 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 daquela imediatamente após a -sopção, basta percorrer a $COMP_WORDSmatriz $COMP_CWORDaté encontrar uma opção (sequência que corresponda -*) e, se for "-s", você precisa concluir o nome do servidor.

Guss
fonte