Hace unos días analizamos cómo tratar los argumentos de entrada desde un shell script en Bash de una manera sencilla. Aunque, cuando la cosa se complica, debemos utilizar herramientas algo más avanzadas. Tal y como hicimos con getopt para C [parte 1, parte 2], vamos a hacer lo mismo en un shell script.
Aunque aquí tenemos dos posibilidades, que hacen prácticamente lo mismo getopt y getopts. Vamos a verlas detenidamente.
Tabla de contenidos
El programa de ejemplo
En este ejemplo, vamos a imaginar que el script hace una copia de seguridad. Dicha copia de seguridad, tendrá varios argumentos de entrada:
- -v : Escribe en pantalla todo lo que está haciendo en cada momento
- -l [archivo] : Escribe un log en el archivo
- -z : Comprime la copia de seguridad
- -c : Copia remotamente el backup a un servidor
- -h : Servidor donde vamos a copiar el backup
Además, debemos decirle los directorios que vamos a copiar. Al menos uno será obligatorio. Además, si se especifica -c, será también obligatorio especificar -h.
getopts, terminado en s
Es el más sencillo, básicamente el uso de getopts lo haremos para no complicarnos la vida cuando un argumento tiene parámetro o no, ya que no tenemos que hacer shift como pasaba en la parte 1 de este tutorial.
Veamos un fragmento de código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #!/bin/bash VERBOSE=0 COPIAREMOTA=0 while getopts vzcl:h: option; do case $option in v) VERBOSE=1 ;; z) COMPRIMIDO=1 ;; c) COPIAREMOTA=1 ;; l) LOGFILE=$OPTARG ;; h) HOSTCOPY=$OPTARG ;; esac done if [ $COPIAREMOTA -eq 1 ] && [ -z "$HOSTCOPY" ] then echo "Si especifica copia remota -c DEBE especificar también host (-h)" exit 1 fi shift $(( OPTIND - 1 )); if [ $# -le 0 ] then echo "Por favor, especifique los directorios a copiar" exit 1 fi echo "VERBOSE: $VERBOSE" echo "COMPRIMIDO: $COMPRIMIDO" echo "LOGFILE: $LOGFILE" echo "COPIA REMOTA: $COPIAREMOTA" echo "HOSTCOPY: $HOSTCOPY" echo "Directorios a copiar: $@" |
El formato de utilización de getopts es:
getopts FORMATO VARIABLE [ARGS]
donde,
- FORMATO será una cadena donde especificaremos los argumentos que serán flags, es decir, los que no necesitan nada más, y los que necesitan un segundo argumento para definir su funcionalidad. Estos últimos, vendrán acompañados de dos puntos (:).
- VARIABLE será la variable de nuestro shell script donde almacenaremos el argumento que está analizándose ahora mismo
- ARGS, si se especifica, indica de dónde se van a sacar los argumentos. Por defecto son los parámetros posicionales $1, $2, $3…
Lo bueno de utilizar getopts y no utilizar los métodos de la primera parte del tutorial es, además, que podemos combinar varios argumentos de entrada en un mismo argumento físico. Dicho de otra forma, no tenemos por qué llamar al programa así:
./test -v -z -c -h SERVIDOR directorio1, directorio2, …, directorioN
podemos hacerlo así:
./test vzch SERVIDOR directorio1, directorio2, …, directorioN
y esto lo hace mucho más amigable al usuario.
El gran problema de getopts, es que si los directorios a copiar los ponemos al principio, o incluso en medio, esos argumentos no se parsearán, y tal vez el comportamiento del programa no sea el deseado.
getopt, sin s, el más flexible
Pero claro, si queremos que nuestro programa acepte argumentos largos (–verbose para -v ; –zip para -z ; –copy para -c ; –log para -l ; –host para -h ) y, además, no queremos tener el problema de que el resto de argumentos se especifiquen en cualquier lugar (al principio, en medio o al final), la solución es getopt, sin s. Con esta utilidad, lo malo es que tenemos que andarnos con los shift de nuevo, pero yo creo que la flexibilidad que nos brinda compensa ese pequeño dolor.
Veamos un ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #!/bin/bash ARGS=$(getopt -q -o "vzcl:h:" -l "verbose,zip,copy,log:,host:" -n "argumentos" -- "$@"); if [ $? -ne 0 ]; then echo "Ha habido un error al parsear los argumentos" exit 1 fi eval set -- "$ARGS"; VERBOSE=0 COPIAREMOTA=0 while [ $# -gt 0 ]; do case "$1" in -v|--verbose) VERBOSE=1 ;; -z|--zip) COMPRIMIDO=1 ;; -c|--copy) COPIAREMOTA=1 ;; -l|--log) LOGFILE="$2" shift; ;; -h|--host) HOSTCOPY="$2" shift; ;; --) shift; break; ;; esac shift done if [ $COPIAREMOTA -eq 1 ] && [ -z "$HOSTCOPY" ] then echo "Si especifica copia remota -c DEBE especificar también host (-h)" exit 1 fi if [ $# -le 0 ] then echo "Por favor, especifique los directorios a copiar" exit 1 fi echo "VERBOSE: $VERBOSE" echo "COMPRIMIDO: $COMPRIMIDO" echo "LOGFILE: $LOGFILE" echo "COPIA REMOTA: $COPIAREMOTA" echo "HOSTCOPY: $HOSTCOPY" echo "Directorios a copiar: $@" |
Viendo esto, getopt, en realidad lo que hace es reordenar los argumentos, es decir, los argumentos que estén juntos (por ejemplo -cvzl) los separa (quedando -c -v -z -l), para que los podamos analizar mejor. Además, los argumentos que no tengan ninguna clave primero, vamos los que quedan sueltos, los pone al final, después de un último argumento «–» (dos guiones, WordPress me pone un guión sólo y me da cosa quitarlo)
Entonces, podemos analizar los argumentos desde la salida de getopt, no sin antes pasar esa variable a los argumentos posicionales (con eval set — «$ARGS»). Cuando estemos analizando, es importante marcar un fin al while, como en el ejemplo, no encontrar más argumentos de entrada, aunque si encontramos «–» hacemos un break y salimos, pero nunca se sabe lo que puede pasar en las salidas, o si un IFS se nos va de madre…
O si preferimos, podemos hacerlo con un for sobre los mismos argumentos, y olvidarnos del case, aunque también tiene sus contras, si queremos extraer los archivos sueltos, debemos hacerlo de otra forma también:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #!/bin/bash ARGX=($(getopt -q -o "vzcl:h:" -l "verbose,zip,copy,log:,host:" -n "argumentos" -- "$@")); if [ $? -ne 0 ]; then echo "Ha habido un error al parsear los argumentos" exit 1 fi VERBOSE=0 COPIAREMOTA=0 for (( arg=0; $arg<$# ; arg++ )) do case "${ARGX[$arg]}" in -v|--verbose) VERBOSE=1 ;; -z|--zip) COMPRIMIDO=1 ;; -c|--copy) COPIAREMOTA=1 ;; -l|--log) ((arg++)) LOGFILE="${ARGX[$arg]}" ;; -h|--host) ((arg++)) HOSTCOPY="${ARGX[$arg]}" ;; --) ULTIMO=$arg+1; break; ;; esac done if [ $COPIAREMOTA -eq 1 ] && [ -z "$HOSTCOPY" ] then echo "Si especifica copia remota -c DEBE especificar también host (-h)" exit 1 fi if [ $# -le 0 ] then echo "Por favor, especifique los directorios a copiar" exit 1 fi echo "VERBOSE: $VERBOSE" echo "COMPRIMIDO: $COMPRIMIDO" echo "LOGFILE: $LOGFILE" echo "COPIA REMOTA: $COPIAREMOTA" echo "HOSTCOPY: $HOSTCOPY" echo "Directorios a copiar: " for ((dir=$ULTIMO; $dir<$#; dir++)) do echo ${ARGX[dir]} done |
Extra, getopts en KornShell
En Twitter, Ingenieria.inversa() nos envía su versión para KornShell utilizando getopts. Aquí tenéis el código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #!/bin/ksh if [ $# == 9 ] then exit 1 else for op in `echo "$@"` do if [[ $op == -* ]] && [[ $op != -[hmps] ]] then OPS="$OPS $op" fi export OPS done if [ -n "$OPS" ] then if [ ${#OPS} -gt 3 ] then printf "\n ERROR:\tLos paranetros $OPS no son validos.\n" else printf "\n ERROR:\tE1 paranetro $OPS no es valido.\n" fi uso exit 1 else while getopts hm:p:s: flag do case $flag in h) echo "BlablabIa..." ;; m) VAR1="$2" ;; p) case $4 in "uno") VAR2="$4" ;; "dos") VAR2="$4" ;; "tres") VAR2="$4" ;; *) exit 1 ;; esac ;; s) VAR3="$6" ;; *) exit 2 ;; esac done shift $(($OPTIND -1)) fi fi |
Para los curiosos
Algo que podemos probar es que, estas herramientas no están limitadas a los argumentos de entrada al script. Pueden ser argumentos de entrada de una función de Bash, o incluso podremos especificar en una cadena de caracteres lo que queremos que getopt o getopts parsee.
Más info
Getopts tutorial
Command line options
Foto principal: freestocks.org
Pingback: Procesar argumentos de entrada en nuestros shell scripts con getopt | PlanetaLibre /
Pingback: Script para realizar capturas de pantalla rápidas con las opciones que necesito – Poesía Binaria /
This is the ultimate destination for anyone seeking the thrill of the biggest web slots. สล็อตเว็บใหญ่ สุด
Are there any reviews on durable slot options available? สล็อตเว็บตรง แตกง่าย
And i’m glad reading your article. But should remark on some general things, The web site style is perfect, the articles is really great : D. Good job, cheers internet providers Edmonton
What a great accomplishment! เว็บคาสิโน ไม่ผ่านเอเย่นต์
Recorded here you’ll learn it is imperative, them offers the connection in an accommodating page: เว็บรวมสล็อตทุกค่าย
Thanks for this great post, i find it very interesting and very well thought out and put together. I look forward to reading your work in the future. Ergonomic Office Chair
You there, this is really good post here. Thanks for taking the time to post such valuable information. Quality content is what always gets the visitors coming. office furniture
You always make me see things in a better way.คาสิโนวอเลท
What is meant by eagle scout applications in the first place? I was hoping to find some information on the subject on https://www.airslate.com/workflows/document/hobbies-and-interests, but that wasn’t forthcoming. Hopefully, I’ll find some other information.What is meant by eagle scout applications in the first place? I was hoping to find some information on the subject on https://www.airslate.com/workflows/document/hobbies-and-interests, but that wasn’t forthcoming. Hopefully, I’ll find some other information.
I no uncertainty esteeming each and every bit of it. It is an amazing site and superior to anything normal give. I need to grateful. Marvelous work! Every one of you complete an unfathomable blog, and have some extraordinary substance. Keep doing stunning. สล็อตโรม่า
I’ve legitimate chosen to assemble a blog, which I hold been inadequate to improve the situation an amid. Recognizes for this advise, it’s extremely serviceable! Pokdeng
Some SMM panels offer white label solutions, allowing resellers to brand the services as their own. This means that end clients may not be aware of the original source of the services.
SMM Panel
Se você está interessado em comprar um mini porco comprar algumas orientações que podem ajudá-lo a encontrar um mini porco de estimação.
mini porco comprar
My comfort comes from a website called https://www.signnow.com/esignature/how-to-esign-a-pdf. I literally got everything in my hands in record time. Highly recommended!
Incredible post I should state and much obliged for the data. Instruction is unquestionably a sticky subject. Be that as it may, is still among the main themes of our opportunity. I value your post and anticipate more. concierge doctor naples
hi was just seeing if you minded a comment. i like your website and the thme you picked is super. I will be back. tradesviz avis
Thank you for your very good information and feedback from you. san jose car dealers click me
thanksssssssss hggjhjhk