Estoy confundido sobre cómo incluir argumentos / indicadores opcionales al escribir un script bash para el siguiente programa:
El programa requiere dos argumentos:
run_program --flag1 <value> --flag2 <value>
Sin embargo, hay varias banderas opcionales:
run_program --flag1 <value> --flag2 <value> --optflag1 <value> --optflag2 <value> --optflag3 <value> --optflag4 <value> --optflag5 <value>
Me gustaría ejecutar el script bash de modo que tome argumentos del usuario. Si los usuarios solo ingresan dos argumentos en orden, entonces sería:
#!/bin/sh
run_program --flag1 $1 --flag2 $2
Pero, ¿qué pasa si se incluye alguno de los argumentos opcionales? Yo pensaría que sería
if [ --optflag1 "$3" ]; then
run_program --flag1 $1 --flag2 $2 --optflag1 $3
fi
Pero, ¿qué pasa si se dan $ 4 pero no $ 3?
shell-script
arguments
ShanZhengYang
fuente
fuente
getopts
es lo que quieres Sin eso, podría usar un bucle con una instrucción switch para detectar cada bandera, opcional o no.getopts
, ¿necesitaría especificar cada combinación de argumentos? 3 y 4, 3 y 5, 3 y 4 y 5, etc.getopts
. Digamos que fuerzo a los usuarios a ejecutar el script con todos los argumentos:run_program.sh VAL VAL FALSE FALSE FALSE FALSE FALSE
que ejecuta el programa comoprogram --flag1 VAL --flag2 VAL
. Si ejecutórun_program.sh VAL VAL FALSE 10 FALSE FALSE FALSE
, el programa se ejecutará comoprogram --flag1 VAL --flag2 VAL --optflag2 10
. ¿Cómo puedes conseguir ese comportamientogetopts
?Respuestas:
Este artículo muestra dos formas diferentes
shift
ygetopts
(y analiza las ventajas y desventajas de los dos enfoques).Con
shift
su secuencia de comandos observa$1
, decide qué acción tomar y luego ejecutashift
, se mueve$2
a$1
,$3
a$2
, etc.Por ejemplo:
Con
getopts
usted define las opciones (cortas) en lawhile
expresión:Obviamente, estos son solo fragmentos de código, y he omitido la validación, verificando que los argumentos obligatorios flag1 y flag2 estén configurados, etc.
El enfoque que utiliza es, en cierta medida, una cuestión de gustos: qué tan portátil desea que sea su script, si puede vivir solo con opciones cortas (POSIX) o si desea opciones largas (GNU), etc.
fuente
while (( $# ))
lugar de hacerlowhile :;
y, a menudo, abandono con un error en el*
casoset -o nounset
la primera solución, se producirá un error si no se proporciona ningún parámetro. Arreglo:case ${1:-} in
usa una matriz.
esto manejará argumentos con espacios en ellos correctamente.
[editar] Estaba usando la sintaxis más o menos equivalente,
args=( "${args[@]}" --optflag1 "$3" )
pero G-Man sugirió una mejor manera.fuente
args+=( --optflag1 "$3" )
. Es posible que desee ver mi respuesta a nuestro trabajo de referencia, Implicaciones de seguridad de no citar una variable en shells bash / POSIX , donde analizo esta técnica (de construir una línea de comando en una matriz agregando condicionalmente argumentos opcionales).[@]
que tenía una herramienta suficiente para resolver mi problema.En un script de shell, los argumentos son "$ 1", "$ 2", "$ 3", etc. El número de argumentos es $ #.
Si su script no reconoce las opciones, puede omitir la detección de opciones y tratar todos los argumentos como operandos.
Para reconocer las opciones, use los getopts incorporados
fuente
Si sus opciones de entrada son posicionales (sabe en qué lugares se encuentran) y no se especifican con banderas, entonces lo que desea es construir la línea de comando. Simplemente prepare los argumentos de comando para todos ellos:
Si no se especifican los parámetros, las cadenas correspondientes están vacías y se expanden en nada. Tenga en cuenta que en la última línea, no hay comillas. Esto se debe a que desea que el shell divida los parámetros en palabras (para dar
--flag1
y$1
como argumentos separados a su programa). Por supuesto, esto saldrá mal si sus parámetros originales contienen espacios. Si usted es el que ejecuta esto, puede dejarlo, pero si se trata de un script general, puede tener un comportamiento inesperado si el usuario ingresa algo con espacios. Para manejar eso, deberás hacer que el código sea un poco más feo.El
x
prefijo en el[]
ensayo es allí en caso de$3
o$4
está vacía. En ese caso, bash se expandiría[ FALSE != $3 ]
en[ FALSE != ]
un error de sintaxis, por lo que hay otro personaje arbitrario para evitar esto. Esta es una forma muy común, lo verá en muchos scripts.Lo configuré
OPTFLAG1
y el resto de ellos al""
principio solo para estar seguro (en caso de que se establecieran algo antes), pero si en realidad no se declararon en el entorno, entonces no es necesario que lo haga estrictamente.Un par de comentarios adicionales:
runprogram
hace: con banderas. De eso es de loJohn N
que estamos hablando. Ahí es donde segetopts
vuelve útil.-
) para señalar un valor vacío, o simplemente pasar una cadena vacía, como""
, si ese no es un valor válido del parámetro. La cadena vacía también hace que la prueba sea más corta, solo utilícelaif [ -n "$3" ]
.""
parámetros vacíos, como se sugirió anteriormente, puede omitir todos los vacíos finales de todos modos.Este método es más o menos la forma en que las opciones se pasan a los compiladores en Makefiles.
Y de nuevo, si las entradas pueden contener espacios, se pone feo.
fuente