Linux

Cron en Linux: cómo programar tareas automáticas paso a paso

Portada del artículo «Cron: programar tareas automáticas» de Trucos Informáticos, categoría Linux

Cron es el programador de tareas de Linux: un servicio que lleva décadas ejecutando comandos a la hora exacta que le pidas. Su sintaxis de cinco columnas asusta el primer día y se domina el segundo, pero tiene varias particularidades que explican el típico «funciona a mano y no desde cron». Esta guía cubre desde el primer crontab hasta los detalles que evitan los fallos silenciosos: entorno, registros, solapamientos y cambios de hora.

Editar tu crontab

crontab -e        # editar las tareas de tu usuario
crontab -l        # listarlas
sudo crontab -e   # las de root
crontab -l -u ana # ver las de otro usuario (requiere sudo)

La primera vez te preguntará qué editor usar: elige nano si no vives en vim. Una advertencia importante: crontab -r borra todas tus tareas sin pedir confirmación, y está justo al lado de -e en el teclado. Si quieres una red de seguridad, haz una copia con crontab -l > ~/crontab.bak antes de editar.

Además del crontab de cada usuario existen las tareas del sistema: el archivo /etc/crontab y los archivos de /etc/cron.d/ (que incluyen una columna extra con el usuario que ejecuta la tarea), y las carpetas /etc/cron.hourly, cron.daily, cron.weekly y cron.monthly, donde basta con dejar un script ejecutable. Un detalle que desconcierta: en Debian y Ubuntu, run-parts ignora los archivos cuyo nombre contiene un punto, así que un script llamado backup.sh en cron.daily no se ejecutará; llámalo simplemente backup.

La sintaxis: cinco columnas y un comando

# ┌ minuto (0-59)
# │ ┌ hora (0-23)
# │ │ ┌ día del mes (1-31)
# │ │ │ ┌ mes (1-12)
# │ │ │ │ ┌ día de la semana (0-7, 0 y 7 = domingo)
# │ │ │ │ │
# * * * * *  comando

En cada columna puedes usar un número, un asterisco (cualquier valor), una lista separada por comas (1,15), un rango (1-5) o un paso (*/10, «cada 10»). También existen atajos como @reboot, @hourly, @daily, @weekly y @monthly.

Una trampa que sorprende incluso a quien lleva años: si rellenas a la vez el día del mes y el día de la semana, cron ejecuta la tarea cuando se cumpla cualquiera de las dos condiciones, no ambas. 0 9 1 * 1 no significa «el día 1 si es lunes», sino «el día 1 de cada mes y también todos los lunes».

Ejemplos listos para copiar

0 7 * * *         /home/usuario/backup.sh           # cada día a las 7:00
*/15 * * * *      /home/usuario/comprobar.sh        # cada 15 minutos
*/10 9-18 * * 1-5 /home/usuario/vigilar.sh          # cada 10 min, de 9 a 18 h, de lunes a viernes
0 3 * * 0         /home/usuario/limpieza.sh         # domingos a las 3:00
0 9 1 * *         /home/usuario/informe-mensual.sh  # el día 1 de cada mes a las 9:00
30 2 1,15 * *     /home/usuario/quincenal.sh        # los días 1 y 15 a las 2:30
@reboot           /home/usuario/al-arrancar.sh      # al iniciar el sistema

Los errores que comete todo el mundo

  • Rutas relativas. Cron no conoce tu carpeta actual y su PATH es muy reducido: usa rutas absolutas para comandos y archivos (/usr/bin/python3 /home/usuario/script.py, no python3 script.py). Averigua la ruta de un comando con which python3.
  • Sin permisos de ejecución. El script necesita chmod +x y una primera línea (shebang) como #!/bin/bash.
  • El % sin escapar. En crontab, el símbolo % tiene significado especial (se convierte en salto de línea): escríbelo como \%, algo típico en comandos con date +\%F.
  • Variables de entorno que no existen. Cron no carga tu .bashrc ni tus variables. Si el script depende de ellas, defínelas dentro del propio script o al principio del crontab.
  • Usar sintaxis de bash en un shell que no lo es. Por defecto cron ejecuta los comandos con /bin/sh. Si necesitas características de bash, añade SHELL=/bin/bash al principio del archivo.

Una cabecera recomendable para cualquier crontab es:

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""

MAILTO define a quién se envía la salida de cada tarea por correo (si el sistema tiene correo configurado). Déjalo vacío para desactivar los correos, o pon tu dirección si quieres recibirlos. Si no tienes correo configurado, los avisos se acumulan en el buzón local del usuario sin que lo notes.

Guardar la salida para saber qué pasó

0 7 * * * /home/usuario/backup.sh >> /var/log/backup.log 2>&1

El >> añade la salida al final del archivo y 2>&1 envía también los errores al mismo registro. Sin esto, cuando una tarea falle de madrugada no tendrás ni idea de por qué. Asegúrate de que el usuario que ejecuta la tarea puede escribir en esa ruta; para tareas de usuario, un registro en tu carpeta personal evita problemas de permisos.

Comprobar que cron hizo su trabajo

# Ubuntu/Debian
grep CRON /var/log/syslog | tail -20
# Sistemas con systemd
journalctl -u cron --since today
# En Fedora, RHEL y derivadas el servicio se llama crond
journalctl -u crond --since today
# ¿Está el servicio activo?
systemctl status cron

Estos registros muestran que cron lanzó el comando, no que el comando tuviera éxito: para saber si terminó bien necesitas el registro propio del script, como el del apartado anterior.

Cómo probar un comando antes de programarlo

La mayoría de fallos se deben a que el entorno de cron es distinto al de tu terminal. Para reproducirlo, ejecuta el script con un entorno vacío:

env -i /bin/sh -c '/home/usuario/backup.sh'

Si falla así, fallará en cron. Otra técnica útil: programa la tarea para dentro de dos minutos, comprueba el registro y, cuando funcione, cámbiala a su horario definitivo.

Evitar que dos ejecuciones se solapen

Si una tarea frecuente tarda más que su intervalo, se acumulan ejecuciones simultáneas que pueden saturar el servidor o corromper datos. La solución habitual es flock, que impide arrancar una segunda instancia mientras la primera sigue activa:

*/5 * * * * flock -n /tmp/sincronizar.lock /home/usuario/sincronizar.sh >> /home/usuario/sincronizar.log 2>&1

Un ejemplo completo: copia de seguridad con rotación

#!/bin/bash
# /home/usuario/backup.sh
set -euo pipefail
ORIGEN="/home/usuario/documentos"
DESTINO="/mnt/copias"
FECHA="$(date +%F)"

tar -czf "$DESTINO/documentos-$FECHA.tar.gz" "$ORIGEN"
# Conservar solo las copias de los últimos 14 días
find "$DESTINO" -name 'documentos-*.tar.gz' -mtime +14 -delete
echo "$(date '+%F %T') copia terminada"
chmod +x /home/usuario/backup.sh
crontab -e
# Añadir:
0 2 * * * /home/usuario/backup.sh >> /home/usuario/backup.log 2>&1

Revisa con cuidado cualquier find ... -delete antes de programarlo: ejecútalo primero sin -delete para ver qué archivos seleccionaría. Una copia de seguridad que nunca has restaurado es solo una esperanza, así que prueba también a recuperar un archivo de vez en cuando.

Zona horaria y cambios de hora

Cron usa la zona horaria del sistema (consúltala con timedatectl). En los cambios de hora de verano e invierno, una tarea programada en la hora que «no existe» puede no ejecutarse, y la que cae en la hora repetida puede ejecutarse dos veces. Para tareas críticas, evita las franjas de las 2:00-3:00 de los días de cambio, o configura el servidor en UTC, que no tiene cambios de hora.

Límites, permisos y seguridad

  • Los archivos /etc/cron.allow y /etc/cron.deny controlan qué usuarios pueden tener crontab.
  • No programes como root lo que puede ejecutar un usuario normal: si el script es modificable por otros, estarás regalando permisos de administrador.
  • Los scripts de cron no deberían ser escribibles por todos (chmod 755, no 777).
  • No pongas contraseñas en la propia línea de cron: aparecen en la lista de procesos. Usa un archivo de credenciales con permisos 600.

Alternativas: systemd timers y at

En distribuciones modernas puedes usar temporizadores de systemd, que ofrecen registro integrado en journalctl, dependencias entre servicios y ejecución de tareas pendientes si el equipo estaba apagado (Persistent=true). Para algo que solo se ejecuta una vez, el comando at (por ejemplo, at 22:30) es más cómodo. Y en un portátil que se apaga a menudo, anacron recupera las tareas diarias o semanales perdidas. Cron sigue siendo la opción más sencilla y universal.

Para seguir aprendiendo

Si estás empezando con la terminal, repasa los comandos básicos de la terminal de Linux, que usarás en tus scripts. En el mundo Windows el equivalente es el Programador de tareas, que se maneja con comodidad desde PowerShell, como explicamos en la guía para programar tareas con PowerShell. Y si estás montando tu primer servidor, una buena práctica es programar la renovación y las copias del servidor web con Apache en Ubuntu.

Preguntas frecuentes

¿Cómo ejecuto una tarea cada 90 segundos o con un intervalo que no encaja?

Cron trabaja con resolución de un minuto y no admite intervalos arbitrarios. Para intervalos distintos, programa la tarea cada minuto y que el propio script decida si le toca, o usa un temporizador de systemd.

¿Por qué mi tarea funciona a mano y no desde cron?

Casi siempre por el entorno: rutas relativas, variables que no existen, shell distinto o permisos. Reprodúcelo con env -i como se explicó antes y revisa el registro de la tarea.

¿Cómo elimino una sola tarea?

Abre el crontab con crontab -e y borra o comenta con # la línea correspondiente. Evita crontab -r, que borra todo.

Conclusión

Cron es simple, fiable y está en todos los Linux del planeta. Rutas absolutas, salida a un registro, una cabecera con SHELL y PATH, flock para evitar solapamientos y la chuleta de las cinco columnas a mano: con eso tienes automatización de nivel profesional con una sola línea de texto.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *