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
ytrabajo_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
degrep
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.