Completar bash para valores separados por comas

16

Me gustaría crear una regla de finalización para la lista de parámetros separados por comas. Por ejemplo, tengo un comando que recibe la lista de nombres de servidores:

myscript -s name1,name2,name3

En este momento he logrado escribir después de completar:

_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
}

Pero tiene al menos 2 problemas:

  1. Las sugerencias para el valor actual incluyen todos los valores anteriores en su prefijo.
  2. No considera valores duplicados.

¿Cuáles son las mejores prácticas para tales casos? ¿Quizás bash-completions tiene algunas funciones incluidas para las listas csv?

diffycat
fuente
3
Lo que podría ayudar es que puede dividir los valores separados por comas en una lista iterable como esta: IFS=, LIST=("$VARIABLE")donde $ VARIABLE contiene sus valores separados por comas.
Michael Ehrenreich
2
Buena idea @MichaelEhrenreich, pero no debes citar el $VARIABLE, de lo contrario no se romperán las palabras. solo usa IFS=, LIST=($VARIABLE).
Guss

Respuestas:

6

Básicamente, no hay forma de solucionar los problemas que describe, porque bash usa los valores COMPREPLYdirectamente en la pantalla y luego reemplaza el texto del usuario, mientras que para obtener lo que desea, primero debe generar las posibles terminaciones (solo las nombres de servidor, sin el prefijo) para que se muestre bash, luego cuando bash está a punto de reemplazar el texto del usuario con la cadena no conflictiva más larga, necesitará que vuelva a llamar a su script para generar el texto con el prefijo - y bash no tiene facilidades para eso.

Lo mejor que se me ocurre es que COMPREPLYse genere solo la primera palabra con el prefijo completo ( COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) )), de modo que si solo hay una posible finalización, se complete automáticamente correctamente, mientras que si hay más de una posible finalización , bash no eliminará lo que se escribió hasta el momento (porque la primera palabra COMPREPLYtiene el prefijo completo y, por lo tanto, coincide con el texto actualmente escrito y será seleccionado por bash para reemplazar el texto del usuario) y mostrará las opciones sin el prefijo, excepto para esa palabra que ya contiene el prefijo, por lo que la salida se verá así:

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

"apple" como se ordenó en último lugar en las opciones de finalización porque lleva el prefijo que comienza con "b", muy confuso. Así que no recomiendo hacer eso.

Con respecto a los duplicados: para no mostrar duplicados, solo necesita dividir $prefixsu parte (fácil IFS="," prefix_parts=($prefix):) y luego iterar sobre ellos y solo dejar en $serverslos nombres que aún no están listados. Es tedioso escribir, así que no lo mostraré aquí, pero es relativamente trivial, así que estoy seguro de que puedes administrar :-).

Para resumir, no creo que deba usar valores separados por comas para las opciones de entrada, al menos si espera que bash lo ayude a completarlo.

Puede admitir un formato de opciones como este: command -s <server> [<server> [..]]y luego, para completar entradas que no sean la inmediatamente posterior a la -sopción, simplemente escanee a través de la $COMP_WORDSmatriz $COMP_CWORDhasta encontrar una opción (cadena que coincida -*) y si es "-s", entonces debe completar el nombre del servidor.

Guss
fuente