Revista Tecnología

Procesar argumentos de entrada en nuestros shell scripts con getopt

Publicado el 27 abril 2016 por Gaspar Fernández Moreno @gaspar_fm

Procesar argumentos entrada nuestros shell scripts getoptProcesar argumentos de entrada en nuestros shell scripts con getopt

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.

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:

El formato de utilización de getopt s 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:

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:

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


Volver a la Portada de Logo Paperblog