lunes, 24 de abril de 2017

Programación defensiva

Es importante verificar las suposiciones cuando programamos. Esto significa una evaluación cuidadosa del estado de salida de los programas y comandos que se usan en un script. Aquí hay un ejemplo, basado en hechos reales. Un desafortunado administrador de sistemas escribió un script para realizar una tarea de mantenimiento en un importante servidor. El script contenía las siguientes dos líneas de código:

cd $dir_name
rm *

No hay nada intrínsecamente malo en estas dos líneas, siempre que el directorio citado en la variable, dir_name exista. Pero ¿qué ocurre si no es así? En ese caso, el comando cd falla y el script continúa con la siguiente línea y borra los archivos en el directorio de trabajo actual. ¡No es para nada el resultado deseado! Este desafortunado administrador destruyó una parte importante del servidor por esta decisión de diseño.

Veamos algunas formas en que este diseño puede mejorarse. Primero, sería prudente hacer que la ejecución de rm dependea del éxito de cd:

cd $dir_name && rm *

De esta forma, si el comando cd falla, el comando rm no se ejecuta. Esto es mejor, pero aún deja abierta la posibilidad de que la variable, dir_name, esté sin configurar o vacía, lo que daría como resultado el borrado de los archivos en el directorio home del usuario. Esto también podría evitarse comprobando si dir_name realmente contiene el nombre de un directorio existente:

[[ -d $dir_name ]] && cd $dir_name && rm *

A menudo, es mejor terminar el script con un error cuando ocurre una situación como la anterior:

# Delete files in directory $dir_name
if [[ ! -d "$dir_name" ]]; then
    echo "No such directory: '$dir_name'" >&2
    exit 1
fi
if ! cd $dir_name; then
    echo "Cannot cd to '$dir_name'" >&2
    exit 1
fi
if ! rm *; then
    echo "File deletion failed. Check results" >&2
    exit 1
fi

Aquí, comprobamos tanto el nombre, para ver si es el de un directorio existente, como el éxito del comando cd. Si cualquiera falla, se envía un error descriptivo al error estándar y el script termina con un estado de salida de uno para indicar un fallo.

No hay comentarios:

Publicar un comentario