Digamos, tengo un script que se llama con esta línea:
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
o este:
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
¿Cuál es la forma aceptada de este análisis de manera que en cada caso (o alguna combinación de los dos) $v
, $f
y $d
todos se ponen a true
y $outFile
serán iguales a /fizz/someOtherFile
?
zparseopts -D -E -M -- d=debug -debug=d
Y tener ambos-d
y--debug
en la$debug
matrizecho $+debug[1]
devolverá 0 o 1 si se usa uno de esos. Ref: zsh.org/mla/users/2011/msg00350.htmlRespuestas:
Método # 1: Usando bash sin getopt [s]
Dos formas comunes de pasar argumentos par clave-valor son:
Bash Separado por espacio (p. Ej.
--option argument
) (Sin getopt [s])Uso
demo-space-separated.sh -e conf -s /etc -l /usr/lib /etc/hosts
salida de copiar y pegar el bloque de arriba:
Bash Equals-Separated (eg,
--option=argument
) (sin getopt [s])Uso
demo-equals-separated.sh -e=conf -s=/etc -l=/usr/lib /etc/hosts
salida de copiar y pegar el bloque de arriba:
Para comprender mejor,
${i#*=}
busque "Eliminación de subcadenas" en esta guía . Es funcionalmente equivalente a lo`sed 's/[^=]*=//' <<< "$i"`
que llama un subproceso innecesario o lo`echo "$i" | sed 's/[^=]*=//'`
que llama a dos subprocesos innecesarios.Método # 2: Usando bash con getopt [s]
de: http://mywiki.wooledge.org/BashFAQ/035#getopts
limitaciones de getopt (1) (
getopt
versiones anteriores, relativamente recientes ):Las
getopt
versiones más recientes no tienen estas limitaciones.Además, la oferta de shell POSIX (y otros)
getopts
que no tiene estas limitaciones. He incluido ungetopts
ejemplo simplista .Uso
demo-getopts.sh -vf /etc/hosts foo bar
salida de copiar y pegar el bloque de arriba:
Las ventajas de
getopts
son:dash
.-vf filename
en la forma típica de Unix, automáticamente.La desventaja
getopts
es que solo puede manejar opciones cortas (-h
no--help
) sin código adicional.Hay un tutorial de getopts que explica lo que significan todas las sintaxis y variables. En bash, también hay
help getopts
, que podría ser informativo.fuente
getopt
que incluye toda la funcionalidad degetopts
y más.man getopt
en las salidas de Ubuntu 13.04getopt - parse command options (enhanced)
como nombre, por lo que supongo que esta versión mejorada es estándar ahora.getopt
no es una utilidad GNU, es parte deutil-linux
.-gt 0
, elimine sushift
después deesac
, aumente todoshift
por 1 y agregue este caso:*) break;;
puede manejar argumentos no opcionales. Ej: pastebin.com/6DJ57HTc–default
. En el primer ejemplo, noto que si–default
es el último argumento, no se procesa (se considera como no opt), a menos quewhile [[ $# -gt 1 ]]
se establezca comowhile [[ $# -gt 0 ]]
Ninguna respuesta menciona getopt mejorado . Y la respuesta más votada es engañosa: ignora
-vfd
las opciones cortas de estilo (solicitadas por el OP) u opciones después de argumentos posicionales (también solicitados por el OP); e ignora los errores de análisis. En lugar:getopt
de util-linux o anteriormente GNU glibc . 1getopt_long()
la función C de GNU glibc.getopt
no puede hacer esto)script.sh -o outFile file1 file2 -v
(getopts
no hace esto)=
opciones largas de estilo:script.sh --outfile=fileOut --infile fileIn
(permitir que ambas sean largas si se analiza automáticamente)-vfd
(trabajo real si se analiza automáticamente)-oOutfile
o-vfdoOutfile
getopt --test
→ valor de retorno 4.getopt
o de concha incorporadagetopts
son de uso limitado.Las siguientes llamadas
todo vuelve
con lo siguiente
myscript
1 getopt mejorado está disponible en la mayoría de los "sistemas bash", incluido Cygwin; en OS X intente brew install gnu-getopt o
sudo port install getopt
2 las
exec()
convencionesPOSIXno tienen una forma confiable de pasar NULL binario en los argumentos de la línea de comandos; esos bytes finalizan prematuramente laprimera versióndel argumento3 lanzada en 1997 o antes (solo lo rastreé hasta 1997)
fuente
getopt
es el camino a seguir.getopt
es que no se puede usar convenientemente en scripts de envoltura donde uno podría tener pocas opciones específicas para la secuencia de comandos de envoltura, y luego pasar las opciones de la secuencia de comandos no envolvente al ejecutable envuelto, intacto. Digamos que tengo ungrep
contenedor llamadomygrep
y tengo una opción--foo
específica paramygrep
, entonces no puedo hacerlomygrep --foo -A 2
, y tengo el-A 2
pase automáticamentegrep
; Yo necesito hacermygrep --foo -- -A 2
. Aquí está mi implementación además de su solución.man bash
Manera más sucinta
script.sh
Uso:
fuente
while [[ "$#" > 1 ]]
si quiero soportar terminar la línea con una bandera booleana./script.sh --debug dev --uglify fast --verbose
. Ejemplo: gist.github.com/hfossli/4368aa5a577742c3c9f9266ed214aa58./script.sh -d dev -d prod
, resultaría endeploy == 'prod'
. Lo usé de todos modos: P :): +1:./script.sh -d
, no generaría un error, sino que solo se establecería$deploy
en una cadena vacía.de: digitalpeer.com con modificaciones menores
Uso
myscript.sh -p=my_prefix -s=dirname -l=libname
Para comprender mejor,
${i#*=}
busque "Eliminación de subcadenas" en esta guía . Es funcionalmente equivalente a lo`sed 's/[^=]*=//' <<< "$i"`
que llama un subproceso innecesario o lo`echo "$i" | sed 's/[^=]*=//'`
que llama a dos subprocesos innecesarios.fuente
mount -t tempfs ...
. Probablemente se pueda arreglar esto a través de algo comowhile [ $# -ge 1 ]; do param=$1; shift; case $param in; -p) prefix=$1; shift;;
etc.-vfd
las opciones cortas combinadas de estilo.getopt()
/getopts()
es una buena opción. Robado de aquí :fuente
$*
es uso roto degetopt
. (Contiene argumentos con espacios). Vea mi respuesta para un uso adecuado.A riesgo de agregar otro ejemplo para ignorar, aquí está mi esquema.
-n arg
y--name=arg
Espero que sea útil para alguien.
fuente
*) die "unrecognized argument: $1"
o recopilar los argumentos en una variable*) args+="$1"; shift 1;;
.shift 2
, emitiendoshift
dos veces en lugar deshift 2
. Sugirió la edición.Llegué 4 años tarde a esta pregunta, pero quiero retribuir. Utilicé las respuestas anteriores como punto de partida para ordenar mi antiguo análisis de parámetros ad hoc. Luego reescribí el siguiente código de plantilla. Maneja parámetros largos y cortos, utilizando argumentos separados por espacios o =, así como múltiples parámetros cortos agrupados. Finalmente, vuelve a insertar cualquier argumento que no sea param en las variables $ 1, $ 2 .. Espero que sea útil.
fuente
-c1
. Y el uso de=
separar opciones cortas de sus argumentos es inusual ...El asunto de escribir un análisis portátil en scripts es tan frustrante que he escrito Argbash , un generador de código FOSS que puede generar el código de análisis de argumentos para su script y tiene algunas características interesantes :
https://argbash.io
fuente
Mi respuesta se basa en gran medida en la respuesta de Bruno Bronosky , pero mezclé sus dos implementaciones de bash puro en una que uso con bastante frecuencia.
Esto le permite tener opciones / valores separados por espacios, así como valores definidos iguales.
Para que pueda ejecutar su script usando:
tanto como:
y ambos deberían tener el mismo resultado final.
PROS:
Permite tanto -arg = value como -arg value
Funciona con cualquier nombre arg que pueda usar en bash
Pura fiesta. No es necesario aprender / usar getopt o getopts
CONTRAS:
No se pueden combinar args.
Estos son los únicos pros / contras en los que puedo pensar fuera de mi cabeza
fuente
Creo que este es lo suficientemente simple como para usar:
Ejemplo de invocación:
fuente
-a=1
como estilo argc. Prefiero poner primero la opción principal -opciones y luego las especiales con espaciado simple-o option
. Estoy buscando la forma más sencilla de leer argumentos../myscript -v -d fail -o /fizz/someOtherFile -f ./foo/bar/someFile
con su propio script. -d opción no está establecida como d:Ampliando la excelente respuesta de @guneysus, aquí hay un ajuste que permite al usuario usar la sintaxis que prefiera, por ejemplo
vs
Es decir, los iguales se pueden reemplazar con espacios en blanco.
Es posible que esta "interpretación difusa" no sea de su agrado, pero si está creando scripts que son intercambiables con otras utilidades (como es el caso con el mío, que debe funcionar con ffmpeg), la flexibilidad es útil.
fuente
Este ejemplo muestra cómo se utilizan
getopt
yeval
, yHEREDOC
, yshift
para manejar los parámetros de corto y largo plazo con y sin un valor requerido que sigue. Además, la declaración de cambio / caso es concisa y fácil de seguir.Las líneas más significativas del script anterior son estas:
Corto, directo, legible y maneja casi todo (en mi humilde opinión).
Espero que ayude a alguien.
fuente
Te doy la función
parse_params
que analizará los parámetros desde la línea de comandos.--all
es-all
igual a igualall=all
)El siguiente script es una demostración de trabajo de copiar y pegar. Vea la
show_use
función para entender cómo usarparse_params
.Limitaciones:
-d 1
)--any-param
y-anyparam
son equivalenteseval $(parse_params "$@")
debe usarse dentro de la función bash (no funcionará en el ámbito global)fuente
show_use "$@"
EasyOptions no requiere ningún análisis:
fuente
getopts funciona muy bien si # 1 lo tiene instalado y # 2 tiene la intención de ejecutarlo en la misma plataforma. OSX y Linux (por ejemplo) se comportan de manera diferente a este respecto.
Aquí hay una solución (no getopts) que admite indicadores iguales, no iguales y booleanos. Por ejemplo, podría ejecutar su script de esta manera:
fuente
Así es como lo hago en una función para evitar romper getopts run al mismo tiempo en algún lugar más alto en la pila:
fuente
Ampliando la respuesta de @ bruno-bronosky, agregué un "preprocesador" para manejar algunos formatos comunes:
--longopt=val
en--longopt val
-xyz
en-x -y -z
--
para indicar el final de las banderasfuente
Hay varias formas de analizar los argumentos de cmdline (por ejemplo, GNU getopt (no portátil) vs BSD (OSX) getopt vs getopts), todos problemáticos. Esta solución es
=
separador-vxf
Ejemplos: cualquiera de
fuente
Me gustaría ofrecer mi versión de análisis de opciones, que permite lo siguiente:
También permite esto (podría ser no deseado):
Debe decidir antes de usar si = se va a usar en una opción o no. Esto es para mantener el código limpio (ish).
fuente
Solución que conserva argumentos no manejados. Demos incluidas.
Aquí está mi solución. Es MUY flexible y, a diferencia de otros, no debería requerir paquetes externos y maneja los argumentos sobrantes limpiamente.
El uso es:
./myscript -flag flagvariable -otherflag flagvar2
Todo lo que tiene que hacer es editar la línea de banderas válidas. Antepone un guión y busca todos los argumentos. Luego define el siguiente argumento como el nombre de la bandera, por ejemplo
El código principal (versión corta, detallada con ejemplos más abajo, también una versión con error):
La versión detallada con demos de eco incorporadas:
La última, esta falla si se pasa un argumento inválido.
Pros: lo que hace, se maneja muy bien. Conserva argumentos no utilizados que muchas de las otras soluciones aquí no tienen. También permite que se invoquen variables sin definirse manualmente en el script. También permite la prepoblación de variables si no se proporciona un argumento correspondiente. (Ver ejemplo detallado).
Contras: No se puede analizar una única cadena arg compleja, por ejemplo, -xcvf se procesaría como un solo argumento. Sin embargo, podría escribir un código adicional en el mío que agregue esta funcionalidad.
fuente
Quiero enviar mi proyecto: https://github.com/flyingangel/argparser
Simple como eso. El entorno se rellenará con variables con el mismo nombre que los argumentos.
fuente
Tenga en cuenta que
getopt(1)
fue un breve error de vida de AT&T.getopt fue creado en 1984 pero ya enterrado en 1986 porque no era realmente utilizable.
Una prueba del hecho de que
getopt
está muy desactualizado es que lagetopt(1)
página de manual todavía menciona en"$*"
lugar de"$@"
eso, que se agregó a Bourne Shell en 1986 junto con elgetopts(1)
shell incorporado para tratar los argumentos con espacios en el interior.Por cierto: si está interesado en analizar opciones largas en scripts de shell, puede ser interesante saber que la
getopt(3)
implementación de libc (Solaris) yksh93
ambos agregaron una implementación uniforme de opciones largas que admite opciones largas como alias para opciones cortas. Esto causaksh93
y laBourne Shell
de implementar una interfaz uniforme durante largos opciones a travésgetopts
.Un ejemplo de opciones largas tomadas de la página de manual de Bourne Shell:
getopts "f:(file)(input-file)o:(output-file)" OPTX "$@"
muestra cuánto tiempo se pueden usar los alias de opción en Bourne Shell y ksh93.
Vea la página del manual de un Bourne Shell reciente:
http://schillix.sourceforge.net/man/man1/bosh.1.html
y la página del manual para getopt (3) de OpenSolaris:
http://schillix.sourceforge.net/man/man3c/getopt.3c.html
y por último, la página del comando man getopt (1) para verificar los $ * obsoletos:
http://schillix.sourceforge.net/man/man1/getopt.1.html
fuente
Escribí un bash helper para escribir una buena herramienta bash
inicio del proyecto: https://gitlab.mbedsys.org/mbedsys/bashopts
ejemplo:
le dará ayuda:
disfruta :)
fuente
Aquí está mi enfoque: usar regexp.
-qwerty
-q -w -e
--qwerty
=
para proporcionar atributos, pero las coincidencias de atributos hasta encontrar guión + espacio "delimitador", por lo que en--q=qwe ty
qwe ty
hay un atributo-o a -op attr ibute --option=att ribu te --op-tion attribute --option att-ribute
es válidoguión:
fuente
Supongamos que creamos un script de shell llamado de la
test_args.sh
siguiente maneraDespués de ejecutar el siguiente comando:
El resultado sería:
fuente
Use "argumentos" del módulo de los módulos bash
Ejemplo:
fuente
Mezcla de argumentos posicionales y basados en banderas
--param = arg (igual delimitado)
Mezclar libremente banderas entre argumentos posicionales:
Se puede lograr con un enfoque bastante conciso:
--param arg (espacio delimitado)
Por lo general, es más claro no mezclar
--flag=value
y--flag value
peinar.Es un poco difícil de leer, pero aún es válido.
Fuente
fuente
Aquí hay un getopts que logra el análisis con un código mínimo y le permite definir lo que desea extraer en un caso usando eval con subcadena.
Básicamente
eval "local key='val'"
Declara las variables como locales en lugar de globales como la mayoría de las respuestas aquí.
Llamado:
El $ {k: 3} es básicamente una subcadena para eliminar el primero
---
de la clave.fuente
Esto también puede ser útil para saber, puede establecer un valor y si alguien proporciona información, anule el valor predeterminado con ese valor.
myscript.sh -f ./serverlist.txt o simplemente ./myscript.sh (y toma los valores predeterminados)
fuente
Otra solución sin getopt [s], POSIX, antiguo estilo Unix
Similar a la solución que Bruno Bronosky publicó aquí es una sin el uso de
getopt(s)
.La principal característica diferenciadora de mi solución es que permite tener opciones concatenadas juntas como
tar -xzf foo.tar.gz
es igual atar -x -z -f foo.tar.gz
. Y al igual que entar
,ps
etc. el guión principal es opcional para un bloque de opciones cortas (pero esto se puede cambiar fácilmente). Las opciones largas también son compatibles (pero cuando un bloque comienza con uno, se requieren dos guiones iniciales).Código con opciones de ejemplo
Para el uso de ejemplo, vea los ejemplos más abajo.
Posición de opciones con argumentos
Por lo que vale, las opciones con argumentos no son las últimas (solo las opciones largas deben ser). Entonces, por ejemplo, en
tar
(al menos en algunas implementaciones) lasf
opciones deben ser las últimas porque el nombre del archivo sigue (tar xzf bar.tar.gz
funciona perotar xfz bar.tar.gz
no funciona) este no es el caso aquí (ver los ejemplos posteriores).Múltiples opciones con argumentos
Como otra ventaja, los parámetros de las opciones se consumen en el orden de las opciones por los parámetros con las opciones requeridas. Solo mira la salida de mi script aquí con la línea de comando
abc X Y Z
(o-abc X Y Z
):Las opciones largas también se concatenan
Además, también puede tener opciones largas en el bloque de opciones dado que ocurren en último lugar en el bloque. Por lo tanto, las siguientes líneas de comando son todas equivalentes (incluido el orden en que se procesan las opciones y sus argumentos):
-cba Z Y X
cba Z Y X
-cb-aaa-0-args Z Y X
-c-bbb-1-args Z Y X -a
--ccc-2-args Z Y -ba X
c Z Y b X a
-c Z Y -b X -a
--ccc-2-args Z Y --bbb-1-args X --aaa-0-args
Todos estos conducen a:
No en esta solución
Argumentos opcionales
Las opciones con argumentos opcionales deberían ser posibles con un poco de trabajo, por ejemplo, mirando hacia adelante si hay un bloque sin guión; el usuario necesitaría poner un guión delante de cada bloque después de un bloque con un parámetro que tenga un parámetro opcional. Tal vez esto sea demasiado complicado para comunicarse con el usuario, por lo que es mejor que solo requiera un guión principal en este caso.
Las cosas se vuelven aún más complicadas con múltiples parámetros posibles. Aconsejaría no hacer que las opciones intenten ser inteligentes al determinar si un argumento puede ser adecuado o no (por ejemplo, con una opción solo toma un número como argumento opcional) porque esto podría romperse en el futuro.
Personalmente, prefiero opciones adicionales en lugar de argumentos opcionales.
Opción argumentos introducidos con un signo igual
Al igual que con los argumentos opcionales, no soy fanático de esto (por cierto, ¿hay un hilo para discutir los pros / contras de los diferentes estilos de parámetros?) Pero si lo desea, probablemente podría implementarlo usted mismo como lo hizo en http: // mywiki.wooledge.org/BashFAQ/035#Manual_loop con un
--long-with-arg=?*
enunciado de caso y luego quitando el signo igual (esto es, por cierto, el sitio que dice que es posible realizar la concatenación de parámetros con cierto esfuerzo, pero "lo dejó como un ejercicio para el lector "lo que me hizo tomarles la palabra pero empecé desde cero".Otras notas
Compatible con POSIX, funciona incluso en configuraciones antiguas de Busybox con las que tuve que lidiar (por ejemplo
cut
,head
ygetopts
falta).fuente