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
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 comentandogetopts
y luego solo mencionasgetopt
. - @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íagetopts
. Gracias.getopts
no ' ni siquiera hace opciones largas, por lo que nada de esto se aplicaría agetopts
. - 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 sí 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
getopts
interno, pero estás usando el comando/usr/bin/getopt
.