¿Cómo usar getopt en la línea de comandos de bash con solo opciones largas?

Hay un comando getopt en la línea de comandos de bash. getopt se puede usar con opciones cortas (como getopt -o axby "$@") y se puede usar con opciones cortas y largas (como getopt -o axby -l long-key -- "$@"), pero ahora necesito solo opciones largas (es decir, las opciones cortas no existen), sin embargo, el comando getopt -l long-key -- "$@" no analiza la opción --long-key correctamente. Entonces, ¿cómo puedo usar el comando getopt con solo opciones largas? ¿O es imposible o es solo un error del comando getopt?

Comentarios

  • Usted etiqueta para el getopts interno, pero estás usando el comando /usr/bin/getopt.
  • @Anthon Lo siento, he usado la etiqueta incorrecta, pero ' no tengo suficiente reputación para agregar otra etiqueta, que necesita 300 reputaciones. Sin embargo, acabo de eliminar la etiqueta incorrecta.

Respuesta

getopt está perfectamente bien sin tener opciones cortas. Pero debes decirle que no tienes opciones cortas. Es una peculiaridad en la sintaxis – del manual:

Si no -o o --options se encuentra en la primera parte, el primer parámetro de la segunda parte se usa como la cadena de opciones corta.

Eso es lo que sucede en su prueba: getopt -l long-key -- --long-key foo trata --long-key como la lista de opciones -egklnoy y foo como único argumento. Utilice

getopt -o "" -l long-key -- "$@" 

p. ej.

$ getopt -l long-key -o "" -- --long-key foo --long-key -- "foo" $ getopt -l long-key -o "" -- --long-key --not-recognized -n foo getopt: unrecognized option "--not-recognized" getopt: invalid option -- "n" --long-key -- "foo" 

Comentarios

  • ¿El OP ' s mezcla de y getopt infectan tu respuesta? Empiezas comentando getopts y luego solo mencionas getopt.
  • @Anthon Toda mi respuesta es sobre el programa getopt de GNU coreutils, que es de lo que trata la pregunta. I he arreglado el texto que decía getopts. Gracias. getopts no ' ni siquiera hace opciones largas, por lo que nada de esto se aplicaría a getopts .
  • El OP tenía originalmente la etiqueta getopts. No quería cambiar tu respuesta, porque normalmente sabes mucho mejor que yo sobre lo que estás escribiendo 🙂
  • Perdí casi una hora tratando de resolver esto. Me acabas de guardar unos vanos sorbos de café. Gracias … démosle un mejor uso a este café ahora. ☕️

Responder

No sé sobre getopt pero el getopts incorporado se puede usar para manejar solo opciones largas como esta:

while getopts :-: o do case "$o$OPTARG" in (-longopt1) process ;; (-longopt2) process ;; esac; done 

Por supuesto, como está, eso no » No funciona si se supone que las opciones largas tienen argumentos. Sin embargo, se puede hacer, pero, como he aprendido trabajando en esto. Aunque inicialmente lo incluí aquí, me di cuenta de que para las opciones largas no tiene mucha utilidad. En este caso, solo estaba acortando mi case (match) campos por un solo carácter predecible. Ahora, lo que sé, es que es excelente para opciones cortas; es más útil cuando está recorriendo una cadena de longitud desconocida y seleccionando bytes individuales de acuerdo con su cadena de opciones . Pero cuando la opción es arg, no hay mucho que esté haciendo con una for var do case $var in combinación que pueda hacer. Es mejor, Creo que, para simplificarlo.

Sospecho que lo mismo ocurre con getopt pero no sé lo suficiente al respecto como para decirlo con certeza. Dada la siguiente matriz de argumentos, demostraré mi propio analizador de argumentos, que depende principalmente de la relación de evaluación / asignación que «he llegado a apreciar para alias y $((shell=math)).

set -- this is ignored by default --lopt1 -s "some "\"" args" here --ignored and these are ignored \ --alsoignored andthis --lopt2 "and some "`more" --lopt1 and just a few more 

Esa es la cadena de argumentos con la que trabajaré. Ahora:

aopts() { env - sh -s -- "$@" } <<OPTCASE 3<<\OPTSCRIPT acase() case "\$a" in $(fmt=" (%s) f=%s; aset "?$(($f)):";;\n" for a do case "$a" in (--) break;; (--*[!_[:alnum:]]*) continue;; (--*) printf "$fmt" "$a" "${a#--}";; esac;done;printf "$fmt" "--*" ignored) (*) aset "" "\$a";;esac shift "$((SHIFT$$))"; f=ignored; exec <&3 OPTCASE aset() { alias "$f=$(($f${1:-=$(($f))+}1))" [ -n "${2+?}" ] && alias "${f}_$(($f))=$2"; } for a do acase; done; alias #END OPTSCRIPT 

Eso procesa la matriz arg en una de dos formas diferentes dependiendo de si le entregas uno o dos conjuntos de argumentos separados por el delimitador --. En ambos casos se aplica a las secuencias de procesamiento de la matriz arg.

Si lo llama como:

: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@" 

Su primer orden de negocio será escribir su función acase() para que se vea así:

acase() case "$a" in (--lopt1) f=lopt1; aset "?$(($f)):";; (--lopt2) f=lopt2; aset "?$(($f)):";; (--*) f=ignored; aset "?$(($f)):";; (*) aset "" "$a";;esac 

Y junto a shift 3.La sustitución de comandos en la definición de la función acase() se evalúa cuando el shell de llamada genera la función «s input here-documents, pero acase() es nunca llamado o definido en el shell de llamada. Se llama en el subshell, aunque, por supuesto, de esta manera puede especificar dinámicamente las opciones de interés en la línea de comando.

Si le entrega un matriz no delimitada simplemente llena acase() con coincidencias para todos los argumentos que comienzan con la cadena --.

La función realiza prácticamente todo su procesamiento en el subshell – guardando iterativamente cada uno de los valores de arg en alias asignados con nombres asociativos. Cuando termina, imprime todos los valores que guardó con alias, que está especificado en POSIX para imprimir todos los valores guardados citados de tal manera que sus valores puedan reintroducirse en el shell. Entonces, cuando lo hago …

aopts --lopt1 --lopt2 -- "$@" 

Su resultado se ve así:

...ignored... lopt1="8" lopt1_1="-s" lopt1_2="some "\"" args" lopt1_3="here" lopt1_4="and" lopt1_5="just" lopt1_6="a" lopt1_7="few" lopt1_8="more" lopt2="1" lopt2_1="and some "`more" 

A medida que recorre la lista de argumentos, comprueba si hay una coincidencia con el bloque del caso. Si encuentra una coincidencia allí, lanza una bandera – f=optname. Hasta que una vez más encuentre una opción válida, agregará cada argumento subsiguiente a una matriz que construya basándose en la bandera actual. Si se especifica la misma opción varias veces, los resultados se componen y no se anulan. Cualquier cosa que no esté en el caso, o cualquier argumento que siga a opciones ignoradas, se asigna a una matriz ignorada .

La salida está protegida por shell para la entrada de shell automáticamente por el shell, y :

eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")" 

… debería ser perfectamente seguro. Si por alguna razón no es seguro, entonces probablemente debería presentar un informe de error a su encargado de shell.

Asigna dos tipos de valores de alias para cada coincidencia. Primero, establece una bandera: esto ocurre si una opción precede o no a argumentos que no coinciden. Por tanto, cualquier aparición de --flag en la lista de argumentos activará flag=1. Esto no es compuesto: --flag --flag --flag solo obtiene flag=1. Sin embargo, este valor se incrementa, para cualquier argumento que pueda seguirlo. Se puede utilizar como clave de índice. Después de hacer el eval anterior, puedo hacer:

printf %s\\n "$lopt1" "$lopt2" 

… para obtener …

8 1 

Y así:

for o in lopt1 lopt2 do list= i=0; echo "$o = $(($o))" while [ "$((i=$i+1))" -le "$(($o))" ] do list="$list $o $i \"\${${o}_$i}\" " done; eval "printf "%s[%02d] = %s\n" $list"; done 

SALIDA

lopt1 = 8 lopt1[01] = -s lopt1[02] = some " args lopt1[03] = here lopt1[04] = and lopt1[05] = just lopt1[06] = a lopt1[07] = few lopt1[08] = more lopt2 = 1 lopt2[01] = and some "`more 

Y a los argumentos que no coinciden, sustituiría ignorado en el campo for ... in anterior para obtener:

ignored = 10 ignored[01] = this ignored[02] = is ignored[03] = ignored ignored[04] = by ignored[05] = default ignored[06] = and ignored[07] = these ignored[08] = are ignored[09] = ignored ignored[10] = andthis 

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *