Cómo programar tareas periódicas con crontab: guía completa desde la sintaxis hasta ejemplos prácticos

DUGLAS MORENODUGLAS MORENO 👁 42

Introducción

En la administración de sistemas y en el desarrollo de software, muchas veces necesitamos ejecutar acciones de forma automática y periódica: hacer copias de seguridad, limpiar archivos temporales, revisar el uso de disco o actualizar paquetes. La herramienta clásica para lograr esto en sistemas Unix‑like es cron, cuya tabla de programación se edita mediante crontab.

Este tutorial está dirigido a administradores de sistemas junior, desarrolladores que trabajan en Linux o macOS y cualquier persona que quiera automatizar tareas sin depender de servicios externos. Al finalizar, sabrás:

  • Qué es cron y cómo funciona su demonio.
  • La sintaxis exacta de los cinco campos de tiempo y los operadores especiales.
  • Cómo editar, listar y eliminar entradas de tu crontab personal y del sistema.
  • Cómo redirigir la salida de los trabajos a archivos de log o recibirla por correo electrónico.
  • Ejemplos reales de scripts Bash que se ejecutan periódicamente, con la salida esperada.

¿Qué es cron y cómo se activa?

Cron es un demonio que se ejecuta en segundo plano y revisa cada minuto si hay alguna entrada en las tablas de crontab que coincida con la hora actual. Cuando encuentra una coincidencia, lanza el comando especificado en un shell separado.

En la mayoría de distribuciones Linux el servicio ya está activo. Podés verificarlo con:

systemctl status cron   # en sistemas basados en systemd
# o
service cron status    # en SysVinit

Si no está activo, lo podés iniciar y habilitar al arranque:

sudo systemctl enable --now cron

En macOS el equivalente se llama launchd, pero aún podés usar crontab para tareas de usuario; el daemon se ejecuta automáticamente.

Sintaxis de los cinco campos

Una línea de crontab tiene este formato:

* * * * * comando_a_ejecutar
- - - - -
| | | | |
| | | | +--- día de la semana (0‑7, donde 0 y 7 son domingo)
| | | +----- mes (1‑12)
| | +------- día del mes (1‑31)
| +--------- hora (0‑23)
+----------- minuto (0‑59)

Cada asterisco representa "todos los valores posibles" para ese campo. Además de números exactos, podés usar los siguientes operadores:

  • * : todos los valores.
  • , : separa valores discretos (ej: 1,3,5 en minutos).
  • - : define un rango (ej: 8-11 para horas).
  • / : paso o intervalo (ej: */15 cada 15 minutos).
  • L : último día del mes o de la semana (solo en día del mes y día de la semana).
  • W : día hábil más cercano al día indicado (solo en día del mes).
  • # : la n‑ésima ocurrencia de un día de la semana en el mes (ej: 2#2 = segundo lunes).

Ejemplos de combinaciones

Expresión Significado
0 2 * * * A las 02:00 todos los días.
*/10 * * * * Cada 10 minutos.
0 0 1 * * Medianoche del primer día de cada mes.
0 0 * * 0 Medianoche cada domingo.
30 4 1-15 * * A las 04:30 los días 1 al 15 de cada mes.
0 0 L * * Medianoche del último día de cada mes.

Edición de crontab

Cada usuario tiene su propia crontab, accesible con el comando crontab -e. Este comando abre el editor definido en la variable de entorno $EDITOR (por defecto suele ser vi o nano).

Abrir el editor

crontab -e

Si es la primera vez que lo usás, el sistema te pedirá elegir un editor. Después de guardar y salir, el demonio cron detecta automáticamente el cambio y vuelve a cargar la tabla.

Listar las entradas actuales

Para ver qué tenés programado sin abrir el editor:

crontab -l

Eliminar toda la crontab

Con crontab -r se borra todo el contenido. Si querés confirmar antes de borrar, usá la opción -i:

crontab -r -i

Editar la crontab de otro usuario (requiere privilegios)

sudo crontab -u otro_usuario -e

Lo mismo vale para listar (-l) o borrar (-r).

Variables de entorno y ruta de ejecución

Los trabajos de cron se ejecutan con un entorno mínimo. No heredan las variables de tu shell interactiva (como $PATH, $HOME o $LANG). Por eso es buena práctica definir explícitamente lo que necesitás al inicio de la crontab:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/home/tu_usuario
MAILTO=tu_usuario@ejemplo.com
  • PATH indica dónde buscar los ejecutables.
  • HOME establece el directorio inicial.
  • MAILTO determina a quién se envía la salida del trabajo por correo (si el sistema tiene un MTA configurado).

Si no definís MAILTO, el correo se envía al propietario de la crontab. Si lo dejás vacío (MAILTO=""), se suprime el envío de correo y solo quedará la salida en el log del sistema (dependiendo de la configuración de rsyslog o journald).

Redirección de salida a archivos de log

Además del correo, es común guardar la salida estándar y de error en un archivo de log para revisarla posteriormente. La redirección se hace dentro del mismo campo de comando:

* * * * * /ruta/al/script.sh >> /var/log/mi_script.log 2>&1
  • >> agrega la salida estándar al final del archivo.
  • 2>&1 redirige el descriptor de error (2) al mismo lugar que la salida estándar (1), de modo que ambos flujos queden en el mismo log.

Si preferís sobrescribir el log en cada ejecución, usá un solo > en lugar de >>.

Envío de correo mediante MTA

Para que cron pueda enviar correos, el sistema necesita un agente de transferencia de correo (MTA) como Postfix, Exim o Sendmail instalado y configurado. En muchas instalaciones de escritorio el MTA no está activo por defecto, pero en servidores suele estar listo.

Podés probar que el envío funciona con:

echo "Prueba de cron" | mail -s "Asunto de prueba" tu_usuario@dominio.com

Si recibís el mensaje, entonces MAILTO en crontab funcionará.

Ejemplos prácticos

A continuación se presentan varios trabajos típicos, cada uno con el script Bash asociado y la salida esperada en el log o en el correo.

1. Copia de seguridad diaria de un directorio

Supongamos que querés hacer un tar comprimido de /var/www/html todos los días a las 02:30 y guardarlo en /backups.

Script de backup (/usr/local/bin/backup_web.sh):

#!/bin/bash
set -euo pipefail

BACKUP_DIR=/backups
SOURCE=/var/www/html
TIMESTAMP=$(date +\%Y\%m\%d\_\%H\%M\%S)
ARCHIVE="${BACKUP_DIR}/web_${TIMESTAMP}.tar.gz"

mkdir -p "$BACKUP_DIR"
tar -czf "$ARCHIVE" "$SOURCE"

 echo "Backup completado: $ARCHIVE"

Hacerlo ejecutable:

sudo chmod +x /usr/local/bin/backup_web.sh

Entrada de crontab (editar con crontab -e):

30 2 * * * /usr/local/bin/backup_web.sh >> /var/log/backup_web.log 2>&1

Salida esperada en /var/log/backup_web.log (ejemplo):

Backup completado: /backups/web_20250925_023000.tar.gz

Si el script falla, el mensaje de error también quedará registrado gracias a 2>&1.

2. Limpieza de archivos temporales más antiguos de 7 días

Queremos borrar de /tmp los archivos que no se hayan modificado en una semana, ejecutándose cada domingo a las 04:00.

Script de limpieza (/usr/local/bin/clean_tmp.sh):

#!/bin/bash
set -euo pipefail

TMP_DIR=/tmp
MAX_DAYS=7

 echo "Iniciando limpieza de $TMP_DIR (archivos > $MAX_DAYS días)" 
find "$TMP_DIR" -type f -mtime +$MAX_DAYS -print -delete
 echo "Limpieza finalizada.

Crontab:

0 4 * * 0 /usr/local/bin/clean_tmp.sh >> /var/log/clean_tmp.log 2>&1

Salida esperada en el log (si hubiera archivos para borrar):

Iniciando limpieza de /tmp (archivos > 7 días)
/tmp/foo12345
/tmp/bar67890
Limpieza finalizada.

Si no hay nada que borrar, solo aparecerán las líneas de inicio y finalización.

3. Monitoreo de uso de disco y envío de alerta por correo

Queremos revisar cada día a las 09:00 el porcentaje de uso de la partición raíz y, si supera el 85 %, enviar un correo de alerta.

Script de chequeo (/usr/local/bin/disk_alert.sh):

#!/bin/bash
set -euo pipefail

THRESHOLD=85
PARTITION="\/
USE=$(df "$PARTITION" | tail -1 | awk '{print $5}' | sed 's/%//')

 if [ "$USE" -ge "$THRESHOLD" ]; then
   SUBJECT="[ALERTA] Uso alto de disco en $(hostname)" 
   BODY="La particion $PARTITION esta al $USE% de uso.
Fecha: $(date)" 
   echo "$BODY" | mail -s "$SUBJECT" "$MAILTO"
 else
   echo "Uso de disco OK: $USE%" 
 fi

Nota: el script usa la variable $MAILTO que definimos en la crontab; si no la definís, el correo se enviará al propietario de la crontab.

Crontab (con variable de entorno):

MAILTO=admin@midominio.com
0 9 * * * /usr/local/bin/disk_alert.sh >> /var/log/disk_alert.log 2>&1

Salida esperada en el log cuando todo está bien:

Uso de disco OK: 62%

Cuando se supera el umbral, además de la línea en el log, recibirás un correo con el asunto y el cuerpo definidos.

4. Actualización automática de paquetes en un servidor Ubuntu

Queremos que cada domingo a las 03:00 se actualicen los paquetes de seguridad y se registre la salida.

Script de actualización (/usr/local/bin/update_security.sh):

#!/bin/bash
set -euo pipefail

LOG_FILE=/var/log/update_security.log

 echo "=== Inicio de actualizacion $(date) ===" >> "$LOG_FILE"
apt-get update -y >> "$LOG_FILE" 2>&1
apt-get upgrade -y --only-upgrade >> "$LOG_FILE" 2>&1
apt-get autoremove -y >> "$LOG_FILE" 2>&1
 echo "=== Fin de actualizacion $(date) ===" >> "$LOG_FILE"

Crontab:

0 3 * * 0 /usr/local/bin/update_security.sh

En este caso no redirigimos explícitamente porque el script ya escribe en su propio log. El correo sólo se enviará si el script produce salida en stderr o stdout y no se captura; como todo va al log, normalmente no habrá correo.

Buenas prácticas

  1. Usar rutas absolutas tanto para el comando como para cualquier archivo que el script necesite.
  2. Definir explícitamente PATH y otras variables al inicio de la crontab para evitar fallos por comandos no encontrados.
  3. Probar el script manualmente antes de programarlo: ejecútalo desde la terminal y verificá su salida y su código de retorno.
  4. Redirigir siempre la salida a un archivo de log o a /dev/null si no la necesitás, para evitar que cron genere correos no deseados cada minuto.
  5. Mantener las entradas pequeñas y legibles: si un trabajo es complejo, poné la lógica en un script separado y llamélo desde la crontab.
  6. Revisar los logs periódicamente para detectar fallos silenciosos.
  7. Usar set -euo pipefail en los scripts Bash para que cualquier error detenga la ejecución y se quede registrado.
  8. Evitar comandos interactivos (como passwd o ssh sin claves) dentro de cron, ya que no habrá terminal para ingresar datos.
  9. Si necesitás variables de entorno específicas (como claves de API), cargalas desde un archivo con permisos restringidos y sourcéalo en el script.
  10. Documentar cada entrada con un comentario al inicio de la línea (usando #) para que quede claro su propósito.

Errores comunes

  • Olvidar hacer ejecutable el script (chmod +x). Cron lo intentará ejecutar pero fallará con "permiso denegado" y el error quedará en el correo de root.
  • Usar rutas relativas dentro del script o la crontab, lo que provoca "no se encontró el archivo o directorio" porque el directorio de trabajo de cron suele ser /.
  • No definir PATH, lo que lleva a errores como "comando no encontrado" aunque el comando exista en /usr/bin.
  • Dejar la salida sin redireccionar, provocando que cron envie un correo cada minuto llenando el buzón de root.
  • Confundir el formato de día de la semana: algunos sistemas usan 0‑7 donde tanto 0 como 7 representan domingo; usar un número fuera de rango hace que la entrada nunca coincida.
  • Olvidar que el entorno de cron es limitado: variables como $HOME, $USER o $DISPLAY pueden no estar definidas.
  • Usar comillas dobles dentro del campo de comando sin escaparlas correctamente, lo que provoca que el shell interprete mal los argumentos.
  • Programar tareas con frecuencia excesiva (por ejemplo * * * * * * con segundos) sin considerar la carga del sistema.

Conclusión

Cron sigue siendo una herramienta poderosa y sencilla para automatizar tareas periódicas en sistemas Unix‑like. Dominar su sintaxis de cinco campos, saber cómo editar y gestionar la crontab, y aplicar buenas prácticas de redirección y manejo de errores te permitirá crear jobs confiables que se ejecuten sin intervención humana.

En este tutorial vimos:

  • La estructura de los cinco campos y los operadores especiales (* , - / L W #).
  • Cómo usar crontab -e, -l y -r para administrar tus propias tablas y, con sudo, las de otros usuarios.
  • La importancia de definir variables de entorno como PATH, HOME y MAILTO.
  • Dos estrategias para obtener la salida de los trabajos: registro en archivos de log y envío de correo mediante un MTA.
  • Cuatro ejemplos concretos (backup, limpieza de temporales, alerta de disco y actualización de paquetes) con sus scripts Bash y la salida esperada.
  • Una lista de buenas prácticas y los errores más frecuentes que suelen aparecer al comenzar.

Con esta información podés empezar a programar tus propias tareas de mantenimiento, despliegue o monitoreo, adaptando los ejemplos a tus necesidades específicas. ¡A automatizar!

Próximos pasos

  • Explorar herramientas alternativas como systemd timers para trabajos que requieran más precisión o dependencias.
  • Integrar la salida de tus jobs en sistemas de centralización de logs (ELK, Loki, Splunk).
  • Utilizar lockfiles o flock dentro de los scripts para evitar que una tarea se ejecute simultáneamente si su duración supera el intervalo programado.

Este artículo fue escrito pensando en vos, que querés pasar de ejecutar tareas a mano a tenerlas corriendo como un reloj.

Comentarios (0)

Sé el primero en comentar.

Dejá tu comentario