Recuerdo haber visto en alguna parte una bash
secuencia de comandos que usa case
y shift
recorre la lista de parámetros posicionales, analiza indicadores y opciones con argumentos cuando los encuentra, y los elimina después del análisis para dejar solo los argumentos desnudos, que luego son procesados por el resto del guión.
Por ejemplo, al analizar la línea de comando de cp -R file1 -t /mybackup file2 -f
, primero caminaría a través de los parámetros, reconocería que el usuario ha solicitado descender a directorios por -R
, especificó el objetivo por -t /mybackup
y para forzar la copia -f
y eliminará de la lista de parámetros, dejando el programa a procesar file1 file2
como los argumentos restantes.
Pero parece que no puedo recordar / descubrir el guión que vi cada vez. Solo me gustaría poder hacer eso. He estado buscando en varios sitios y agrego una lista de páginas relevantes que examiné.
Una pregunta en este sitio web preguntó específicamente sobre "opciones independientes del orden", pero tanto la respuesta única como la respuesta a la pregunta a la que fue duplicada no considera casos como el anterior donde las opciones se mezclan con argumentos normales, lo que supongo que fue razón para que la persona mencione específicamente opciones independientes del pedido .
Como bash
la función incorporada getopts
parece detenerse en el primer argumento sin opción, no parece ser suficiente como solución. Es por eso que la página de Wooledge BashFAQ (ver más abajo) explica cómo reorganizar los argumentos. Pero me gustaría evitar crear múltiples matrices en caso de que la lista de argumentos sea bastante larga.
Dado shift
que no admite la aparición de argumentos individuales en el medio de la lista de parámetros, no estoy seguro de cuál es una forma directa de implementar lo que estoy preguntando.
Me gustaría saber si alguien tiene alguna solución para eliminar argumentos del medio de la lista de parámetros sin crear una matriz completamente nueva.
Páginas que ya he visto:
- http://mywiki.wooledge.org/ComplexOptionParsing#Rearranging_arguments
- http://mywiki.wooledge.org/BashFAQ/035
- Uso de getopts en el script de shell bash para obtener opciones de línea de comando largas y cortas
- http://wiki.bash-hackers.org/scripting/posparams
- http://wiki.bash-hackers.org/howto/getopts_tutorial
- argumento de bash para argumentos en $ @
- ¿Cuál es la forma canónica de implementar opciones independientes del orden en los scripts de bash?
- ¿Cómo manejo los interruptores en un script de shell?
Respuestas:
POSIXY, el análisis de las opciones debe detenerse en
--
el primer argumento sin opción (o sin argumento de opción), lo que ocurra primero. Entonces enEso es al
file1
, por lo quecp
de forma recursiva deben copiar todosfile1
,-t
,/mybackup
yfile2
en el-f
directorio.getopt(3)
Sin embargo, GNU (que GNUcp
usa para analizar opciones (y aquí está usando GNUcp
ya que está usando la-t
opción específica de GNU )), a menos que se establezca la$POSIXLY_CORRECT
variable de entorno, acepta opciones después de argumentos. Por lo tanto, en realidad es equivalente al análisis de estilo de opción POSIX:El
getopts
shell incorporado, incluso en el shell GNU (bash
) solo maneja el estilo POSIX. Tampoco admite opciones largas u opciones con argumentos opcionales.Si desea analizar las opciones de la misma manera que lo
cp
hace GNU , deberá usar lagetopt(3)
API de GNU . Para eso, si está en Linux, puede usar lagetopt
utilidad mejorada deutil-linux
( esa versión mejorada delgetopt
comando también se ha portado a otros Unices como FreeBSD ).Eso
getopt
reorganizará las opciones de una manera canónica que le permite analizarlo simplemente con unwhile/case
bucle.Normalmente lo usarías como:
También tenga en cuenta que
getopt
analizará las opciones de la misma manera que locp
hace GNU . En particular, admite las opciones largas (y al ingresarlas abreviadas) y respeta las$POSIXLY_CORRECT
variables de entorno (que, cuando se configuran, desactivan el soporte para las opciones después de los argumentos) de la misma manera que locp
hace GNU .Tenga en cuenta que usar gdb e imprimir los argumentos que
getopt_long()
recibe puede ayudar a construir los parámetros paragetopt(1)
:Entonces puedes usarlo
getopt
como:Recuerde que
cp
la lista de opciones compatibles de GNU puede cambiar de una versión a la siguiente y esogetopt
no podrá verificar si pasa un valor legal a la--sparse
opción, por ejemplo.fuente
while [ "$#" -gt 0 ]
io justwhile (($#))
? ¿Es solo para evitar un bashismo?(($#))
es más un kshismo .Por lo tanto, cada vez que
getopts
procesa un argumento, no espera que establezca la variable de shell$OPTIND
en el siguiente número en la lista de argumentos que debe procesar y devuelve otro que no sea 0. Si$OPTIND
se establece en un valor de 1,getopts
se especifica POSIX para aceptar un nueva lista de argumentos Por lo tanto, esto solo observa elgetopts
retorno, guarda los incrementos de un contador más$OPTIND
para cualquier retorno fallido, aleja los argumentos fallidos y restablece$OPTIND
cada intento fallido. Puede usarlo comoopts "$@"
si quisiera personalizar elcase
bucle o guardarlo en una variable y cambiar esa sección aeval $case
.Mientras se ejecuta, establece
$args
todos los argumentos quegetopts
no manejan ... así que ...SALIDA
Esto funciona
bash
,dash
,zsh
,ksh93
,mksh
... bueno, dejar de tratar en ese punto. En cada caparazón también consiguió$[Rtf]flag
y$targ
. El punto es que todos los números para los argumentos quegetopts
no quisieron procesar permanecieron.Cambiar el estilo de opciones tampoco hizo ninguna diferencia. Funcionó como
-Rf -t/mybackup
o-R -f -t /mybackup
. Funcionó en el medio de la lista, al final de la lista, o al principio de la lista ...Aún así, la mejor manera es simplemente pegar un
--
final de opciones en su lista de argumentos y luego hacerloshift "$(($OPTIND-1))"
al final de unagetopts
ejecución de procesamiento. De esa manera, elimina todos los parámetros procesados y mantiene el final de la lista de argumentos.Una cosa que me gusta hacer es traducir las opciones largas a cortas, y lo hago de una manera muy similar, por eso esta respuesta fue fácil, antes de correr
getopts
.fuente
cp -t --file foo
ocp -- --file foo
) y no haría frente a las opciones ingresadas abreviadas (--fi
...), o con la--target=/dest
sintaxis.getopts
cosa con una función mucho más simple.opts()
tiene algo que ver con su propia respuesta, ya queopts()
funciona en un solo bucle, tocando cada argumento pero una vez, y lo hace de manera confiable (lo más cerca que puedo decir) , de forma portátil y sin una sola subshell.-R
,-t /mybackup
,-f
). Mantendré mi voto negativo por ahora, ya que todavía está ofuscado, lo está usando sin$a
inicializar yargs= opts...
es probable que deje sinargs
configurar (o establecer lo que era antes) después deopts
regresar en muchos shells (que incluye bash).bash
- Odio eso. En mi opinión, si la función es una función de shell actual que debería conservarse. Estoy abordando estas cosas, ya que la función actual, con más pruebas, se podría hacer de manera robusta para manejar todos los casos e incluso para marcar el argumento con su opción anterior, pero no estoy de acuerdo con que esté ofuscado . Tal como está escrito, es el medio más simple y directo de cumplir su tarea que se me ocurre.test
ing entoncesshift
ing tiene poco sentido cuando en cadashift
caso fallido deberíasreturn
. No tiene la intención de hacer lo contrario.