domingo, 29 de junio de 2014

Cómo mejorar scripts en bash

Introducción


Si has escrito scripts en algún intérprete de comandos como bash probablemente hayas tenido errores porque al haber escrito mal el nombre de una variable, el intérprete la define en ese momento vacía.

También se te habrá dado el caso de querer interrumpir la ejecución desde que algún comando falle, ya que por defecto, la ejecución de un script no se interrumpe aunque falle algún comando. Por ejemplo, si cambias de directorio (cd) y luego borras ficheros (rm), si falla el comando cd el resultado del comando rm puede ser desastroso.

Parámetros de configuración


El bash se puede configurar para abortar la ejecución de un script si se utiliza una variable que no ha sido inicializada:

#Expresiones equivalentes
set -o nounset
set -u

Esa opción es muy útil y puede evitarte muchos accidentes y quebraderos de cabeza.

También se puede configurar que se interrumpa la ejecución del script si falla algún comando:

#Expresiones equivalentes
set -o errexit
set -e

OJO, se considera fallar que el comando devuelva un valor distinto de 0.

Hay más parámetros que te pueden interesar como "pipefail" por ejemplo.

Ejemplos


Con este pequeño script, activando o desactivando los parámetros anteriores, puedes comprobar tú mismo como cambia el comportamiento del bash:

set -o nounset
set -o errexit
###############################################################################

#echo "Using mode: nounset"
echo "This command is executed: OK."
echo "This command fails because this variable has not been initialized <${VAR_UNDEF}>."
echo "This command is not executed because previous command failed."

#echo "Using mode: errexit"
echo "This command is executed: OK."
#Next command fails because the file doesn't exist.
cat "/tmp/unexistent.file"
echo "This command is not executed because previous command failed."

Si quieres hacer pruebas on-line, puedes usar este enlace:


Observaciones


Respecto al modo "errexit" hay mucha controversia (más abajo hay algunos enlaces si te interesa el tema). Hay que tener muy en cuenta que se aborta cuando un comando devuelve algo distinto de 0, lo cual no tiene por qué significar necesariamente que haya fallado. De hecho, hay comandos que intencionadamente devuelven valores distintos de 0 sin tratarse de errores.

Otra cosa que se comenta por ahí, es que algunas de las características (como "pipefail") van cambiando de una versión de bash a otra.
 

Conclusión


En mi humilde opinión, el modo "nounset" debería ser el comportamiento por defecto, pero bueno, para gustos los colores.

Yo considero que el modo "errexit" es una herramienta muy útil que el programador debe saber cuando usar y cuando no.

A veces interesa buscar si el comportamiento de alguna herramienta es configurable, porque muchas veces, el comportamiento por defecto no nos conviene.

Enlaces


Enlaces de interés relacionados con este artículo:

(Actualizado 29/06/2014)