Skip to content
Sintaxis cron — Guía práctica completa

Fechas y hora

Sintaxis cron — Guía práctica completa

Expresiones cron explicadas: 5 campos, operadores, aliases, la trampa de lógica OR entre día-del-mes y día-de-la-semana, y patrones que cubren el 95% de jobs reales.

Cron ha sido el scheduler por defecto en Unix desde 1975. La sintaxis es mínima, ampliamente mal recordada, y tiene exactamente una sorpresa que pilla a ingenieros cada año. Esta es la referencia que te cabe en la cabeza.

Los cinco campos

Una expresión cron son cinco campos separados por espacios. Algunos sistemas (Quartz, Jenkins, AWS EventBridge) añaden un campo de segundos al inicio o un año al final — esta guía cubre la sintaxis clásica POSIX de cinco campos que corre en /etc/crontab, Kubernetes CronJob, GitHub Actions schedules y la mayoría de schedulers cloud.

┌─────────── minuto (0-59)
│ ┌───────── hora (0-23)
│ │ ┌─────── día del mes (1-31)
│ │ │ ┌───── mes (1-12 o JAN-DEC)
│ │ │ │ ┌─── día de la semana (0-6 o SUN-SAT; 7 == 0 en muchos sistemas)
│ │ │ │ │
* * * * *   comando

0 3 * * * corre a las 03:00 todos los días. */15 * * * * cada 15 minutos. 0 0 1 * * a medianoche el 1 de cada mes.

Los cuatro operadores

Cada campo cron entiende cuatro operadores:

OperadorSignificadoEjemploMatchea
*Cualquier valor* * * * *Cada minuto
,Lista0 9,12,17 * * *09:00, 12:00, 17:00
-Rango0 9-17 * * 1-5Cada hora, 9-17, Lun-Vie
/Paso*/10 * * * *Cada 10 minutos

Los pasos se combinan con rangos: 0 9-17/2 * * * corre a las 9, 11, 13, 15, 17. Pasos solos sobre * son atajo para “empezar en el mínimo y avanzar”: */15 en el minuto es 0,15,30,45.

Los aliases

Una lista corta de aliases de conveniencia definida en Vixie cron y heredada por la mayoría de schedulers modernos:

@yearly   (o @annually)   →  0 0 1 1 *
@monthly                  →  0 0 1 * *
@weekly                   →  0 0 * * 0
@daily    (o @midnight)   →  0 0 * * *
@hourly                   →  0 * * * *
@reboot                   →  una vez al arranque

@reboot no es portable. Kubernetes CronJob, AWS EventBridge y la mayoría de schedulers cloud no lo soportan. Úsalo solo en daemons cron tradicionales (/etc/crontab, crontab -e).

La trampa de lógica OR

Esto es lo que tropieza a ingenieros con experiencia. Cuando especificas TANTO día-del-mes (campo 3) como día-de-la-semana (campo 5), cron corre cuando cualquiera matchea, no cuando ambos.

# Podrías leer esto como "el 1 del mes, solo si es lunes"
0 9 1 * 1
# Cron lo lee: "a las 09:00 el día 1 de cada mes O cada lunes"

Está en POSIX, heredado por Vixie cron, heredado por el default de Linux y macOS. Kubernetes CronJob, GitHub Actions y casi todos los schedulers cloud preservan el mismo comportamiento por compatibilidad.

El workaround es usar * en uno de los dos campos cuando no necesites ambos, y testear con un parser de cron. Si realmente necesitas “primer lunes del mes”, tienes que o bien comprobarlo dentro del job (salir temprano si date +%u no es 1) o usar un scheduler que soporte operadores estilo Quartz con # (1#1 = primer lunes).

Patrones que cubren el 95% de jobs reales

Construye estos en memoria muscular:

# Cada minuto
* * * * *

# Cada 5 minutos
*/5 * * * *

# Cada hora en punto
0 * * * *

# Diario a las 03:00
0 3 * * *

# Semanal domingo a las 04:00
0 4 * * 0

# Mensual el 1 a medianoche
0 0 1 * *

# Laborables (Lun-Vie) a las 09:00
0 9 * * 1-5

# Dos veces al día (08:00 y 20:00)
0 8,20 * * *

# Cada 15 minutos en horario laboral Lun-Vie
*/15 9-18 * * 1-5

# Trimestral (Ene, Abr, Jul, Oct) el 1 a las 00:05
5 0 1 1,4,7,10 *

Para el entorno shell que habitualmente emparejarás con cron, el cheatsheet de bash cubre redirecciones y el linux-cheatsheet tiene los comandos de control del daemon.

El entorno no es tu shell

El bug más común de cron es: “funciona cuando lo ejecuto a mano, pero no funciona como cron job”. El job corre en un entorno pelado. PATH es mínimo. HOME puede estar unset en algunos sistemas. No se sourcea ningún profile de shell.

Siempre:

  • Usa paths absolutos (/usr/bin/python3, no python3).
  • Redirige la salida (>> /var/log/myjob.log 2>&1) para ver qué se traga cron en silencio.
  • Define un PATH= al inicio del crontab si tu job llama a comandos que necesitan paths no-default.
  • Quota con cuidado. El % tiene significado especial (newlines en el stdin enviado al comando); escápalo como \% en el crontab.
PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash
MAILTO=""

# Backup diario a las 02:30
30 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

Zonas horarias

En Linux tradicional, cron corre en la zona del sistema (lo que diga /etc/localtime). En Kubernetes CronJob v1.27+ puedes poner .spec.timeZone: "Europe/Madrid" por job. AWS EventBridge soporta expresiones cron() solo en UTC — conviertes tú.

Si tu scheduler está en una zona y tu equipo en otra, el default más seguro es UTC para todo y hacer la cuenta mental en los bordes. Mira la guía de zonas horarias para el principio general: guarda y programa en UTC, renderiza local.

Testear sin esperar

Tres enfoques, del más rápido al más fiel:

  1. crontab.guru o cualquier parser local de cron. Pega la expresión, ve las siguientes 5 ejecuciones en texto plano.
  2. Cambiar temporalmente el schedule a * * * * * (cada minuto) y mirar el log.
  3. Ejecutar el comando a mano con el entorno de cron: env -i /bin/bash -c 'TU COMANDO' reproduce el entorno vacío de cron.

Conclusiones

Cinco campos, cuatro operadores, una trampa (día-del-mes OR día-de-la-semana). Empareja el job con paths absolutos, redirecciones explícitas y una decisión de timezone que case con el sistema entero. Para la referencia Linux operacional más amplia, mira el linux cheatsheet; para patrones shell que los jobs suelen invocar, el bash cheatsheet.

Herramientas relacionadas

Por ·