sábado, 6 de junio de 2009

HAL y la burocracia (XII - limpieza)

Los buenos profesionales de la construcción, la fontanería o de cualquier otra actividad que interviene en la infraestructura de nuestra casa no dan por finalizado su trabajo hasta haber borrado completamente la huellas de su actividad reformadora. Hoy en día, urgidos por el afán de amasar dinero fácil o, simplemente, carentes de toda ética profesional, son habituales los chapuceros que nos acaban dejando la casa hecha un zaguán.

No vayamos a emular esta desagradable actitud y procuremos que tras la ejecución de nuestro guión todo quede limpio y bien dispuesto.

Por lo general, un guión genera dos tipos de basura: basura permanente, compuesta por ficheros temporales, ya sea creados por nosotros mismos o por las órdenes que lo componen, y basura en pantalla, esto es, mensajes de información que se producen al ejecutar dichas órdenes. Los primeros se eliminan fácilmente con la orden rm; los segundos, redirigiéndolos al agujero negro de HAL.

Estas operaciones de limpieza deben efectuarse solamente una vez que se ha comprobado fehacientemente la corrección de nuestro guión. De hecho, los ficheros temporales y los mensajes producidos en su ejecución son información valiosa para descubrir la fuente de errores potenciales. Y ---conviene recordarlo--- no es probable que un guión esté libre de fallos en su primeras redacciones.

El paso de eliminar los ficheros temporales es, a estas alturas, pan comido. Los ficheros temporales creados por nuestro guión son:

  • Los ficheros objetivos_tmp.tex, contenidos_tmp.tex y trabajo_tmp.tex

  • Los ficheros producidos por pdflatex, cuyo nombre es el mismo que el del fichero pdf resultante: $ALUMNO.pdf, pero con extensiones diferentes: $ALUMNO.tex, $ALUMNO.aux, etc.


La orden para eliminar los ficheros citados en primer lugar puede ser ésta, que borra todos los ficheros cuyo nombre termina en _tmp.tex:

rm *_tmp.tex

Para eliminar los ficheros citados en segundo lugar, podemos utilizar una orden como la siguiente:

rm $(ls ${ALUMNO}* | grep -v '\.pdf')

Esta orden envía la lista de todos los ficheros cuyo nombre comienza por $ALUMNO a grep, que devuelve todos menos el que termina con la extensión pdf ---para eso sirve la opción -v de grep---, y lo filtrado por grep se lo da como argumento a rm.

Para que los mensajes de información emitidos por las órdenes que se ejecutan dentro del guión no aparezcan en pantalla, el recurso habitual es redirigirlos a un fichero especial, llamado /dev/null, un agujero negro dentro de HAL que succiona todo lo que llega a él y lo hace desaparecer en la nada. De las órdenes incorporadas en nuestro guión, pdflatex va a producir siempre mensajes informativos, como habrá comprobado el lector que haya puesto a prueba las versiones del guión dadas hasta ahora. Si no queremos molestar al usuario con estos mensajes, podemos añadir la redirección a /dev/null a dicha orden:

pdflatex ${ALUMNO}.tex > /dev/null

La nueva versión del guión, generar_informes-5, con estas tres medidas higiénicas incluidas, queda así:

# Directorio que contiene la programación del curso
PROGRAMACION="$HOME/guiones/informe_suspensos"

# Fichero que contiene la plantilla LaTeX del informe
PLANTILLA=informe_plantilla.tex

# Fichero que contiene las notas de los alumnos
NOTAS=notas

# Sufijo de los ficheros de objetivos por cursos
OBJETIVOS=objetivos.tex

# Sufijo de los ficheros de contenidos por cursos
CONTENIDOS=minimos.tex

# La nota mínima para aprobar el curso
NOTA_MINIMA=5

# Fichero sed para limpiar etiquetas LaTeX
NOLATEX=limpiar_tex.sed

for linea in $(cat $NOTAS)
do
if [ $(echo $linea | cut -d':' -f3) -lt $NOTA_MINIMA ]
then
# Nombre y curso del alumno tal como constan en el fichero $NOTAS
ALUMNO=$(echo $linea | cut -d':' -f1)
CURSO=$(echo $linea | cut -d':' -f2)

# El nombre del alumno y curso con el formato que tendrán en la salida impresa
ALUMNO_OUTPUT=$(echo $ALUMNO | sed -e 's/-/ /g')
CURSO_OUTPUT=$(echo $CURSO | sed -e 's/\([[:digit:]]*\)-\(.*\)/\1\.º \2/' \
-e 's/ge/EE/' \
-e 's/gm/EP/')

# Ficheros que contienen los objetivos y contenidos del curso
# en que el alumno está matriculado
F_OBJETIVOS=${PROGRAMACION}/${CURSO}-$OBJETIVOS
F_CONTENIDOS=${PROGRAMACION}/${CURSO}-$CONTENIDOS

# Los objetivos y contenidos en un formato apto para la plantilla
# a partir de la que se genera el informe
sed -f $NOLATEX $F_OBJETIVOS > objetivos_tmp.tex
sed -f $NOLATEX $F_CONTENIDOS > contenidos_tmp.tex

# Las propuestas de trabajo se deben introducir interactivamente
echo "Introduzca propuestas de trabajo para $ALUMNO_OUTPUT [\item ... (^D para salir)]: "
cat > trabajo_tmp.tex

sed -e "s/ALUMNO/$ALUMNO_OUTPUT/" \
-e "s/CURSO/$CURSO_OUTPUT/" \
-e 's/OBJETIVOS/\\input{objetivos_tmp}/' \
-e 's/CONTENIDOS/\\input{contenidos_tmp}/' \
-e 's/RECUPERACIÓN/\\input{trabajo_tmp}/' $PLANTILLA > ${ALUMNO}.tex

pdflatex ${ALUMNO}.tex > /dev/null

# Eliminación del los ficheros temporales creados
rm *_tmp.tex
rm $(ls ${ALUMNO}* | grep -v '\.pdf')

fi
done

Las tres únicas diferencias dignas de mención respecto de la versión propuesta al principio de esta serie son:

  • El valor de la variable PROGRAMACION, un valor que lógicamente dependerá del lugar donde el usuario tenga almacenados los ficheros de objetivos y mínimos.

  • La instrucción lp ${ALUMNO}.pdf > /dev/null, que envía el informe del alumno directamente a la impresora, en caso de que el usuario disponga de un sistema de impresión basado en CUPS, lo normal estos días en las distribuciones GNU/Linux.

  • El enigmático #!/bin/sh, que nos acompaña desde el pasado de estas conversaciones, que no es estrictamente necesario en la mayoría de los casos, y cuyo sentido tocará explicar en su momento.


Si el lector ha sido capaz de alcanzar esta cota sin desfallecer, puede considerarse un usuario avanzado y, si le apetece verlo de esta otra forma, un programador en ciernes. Enhorabuena, Sancho, te subiremos la nota.


Resumen:

  • Cuando la corrección de un guión se ha comprobado suficientemente, es recomendable limpiar el directorio desde el que se ejecuta de todos los ficheros temporales generados y suprimir de la interfaz del usuario los mensajes informativos que las órdenes aplicadas pueden generar.

  • La opción -v de grep invierte el sentido de la búsqueda, esto es, devuelve las líneas de la entrada que no encajan con el patrón suministrado como primer argumento.

  • El fichero especial /dev/null existe para redirigir a él cualquier salida de nuestras órdenes que queremos hacer desaparecer del universo visible.

No hay comentarios:

Publicar un comentario