Cómo construir expresiones cron
Las expresiones cron son la forma estándar de definir horarios recurrentes en Linux, plataformas en la nube, pipelines CI/CD y planificadores de tareas. La sintaxis es compacta pero poco intuitiva: construir un generador cron visual te muestra exactamente cuándo se ejecutará tu tarea, atrapa errores comunes antes del despliegue y elimina las conjeturas de la parte más propensa a errores de la automatización. Una vez que comprendes los cinco campos, los caracteres especiales y los errores más comunes, puedes especificar cualquier horario recurrente con confianza.
Breve historia de cron
El primer cron vino de Brian Kernighan en la versión 7 de Unix, alrededor de 1979. Releía su configuración cada minuto y ejecutaba todo lo que estuviera pendiente. Paul Vixie lo reescribió en 1987 en lo que ahora se llama Vixie cron, que es la versión que la mayoría de distribuciones Linux aún llevan. Vixie cron añadió crontabs por usuario, variables de entorno, la palabra clave @reboot y varias características de comodidad que hicieron el formato utilizable para no administradores.
La sintaxis de 5 campos apenas ha cambiado en más de cuarenta años. Amazon EventBridge, Google Cloud Scheduler, Kubernetes CronJob, GitHub Actions, GitLab CI, Jenkins, Airflow, n8n y docenas de otros sistemas consumen el mismo formato compacto con solo extensiones menores. Esa estabilidad es la razón por la que cron vale la pena aprender una vez y nunca volver a aprender. La habilidad se transfiere a todas partes donde la automatización funciona con reloj.
Sintaxis cron
Una expresión cron estándar tiene 5 campos, separados por espacios. Cada campo controla una porción de tiempo, y una tarea se ejecuta cuando cada campo coincide con el momento actual.
┌───────────── 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, Dom=0, o SUN-SAT)
│ │ │ │ │
* * * * *
Los campos se combinan con Y para hora, minuto y mes, pero día-del-mes y día-de-la-semana se combinan con O en Vixie cron. Eso significa que 0 12 1 * 1 se dispara el 1 de cada mes Y cada lunes al mediodía, no solo los lunes que caen el 1. Este truco atrapa a casi todos la primera vez.
Horarios cron comunes
Los patrones a los que recurrirás con más frecuencia:
| Horario | Expresión | Significado |
|---|---|---|
| Cada minuto | * * * * * | Se ejecuta cada 60 segundos |
| Cada 5 minutos | */5 * * * * | A las :00, :05, :10, :15... |
| Cada 15 minutos | */15 * * * * | A las :00, :15, :30, :45 |
| Cada hora | 0 * * * * | Al inicio de cada hora |
| Cada 2 horas | 0 */2 * * * | A las 00:00, 02:00, 04:00... |
| Diario a medianoche | 0 0 * * * | Una vez al día a las 00:00 |
| Diario a las 9 AM | 0 9 * * * | Una vez al día a las 09:00 |
| Dos veces al día | 0 9,21 * * * | A las 09:00 y 21:00 |
| Cada lunes a las 8 AM | 0 8 * * 1 | Semanal los lunes |
| Entre semana a las 6 PM | 0 18 * * 1-5 | De lunes a viernes |
| 1 de cada mes | 0 0 1 * * | Mensual a medianoche el día 1 |
| Cada trimestre | 0 0 1 */3 * | 1 ene, 1 abr, 1 jul, 1 oct |
| Cada mañana entre semana | 0 7 * * 1-5 | 07:00 de lunes a viernes |
| Domingo al mediodía | 0 12 * * 0 | Semanal los domingos |
Muchos sistemas también aceptan alias abreviados que se expanden a la expresión de 5 campos equivalente: @yearly, @monthly, @weekly, @daily, @hourly y @reboot. Son concisos pero no universales, así que verifica tu plataforma antes de confiar en ellos.
Cómo construir una expresión cron
- Elige la granularidad: ¿necesitas cada minuto, cada hora, una vez al día, una vez a la semana o una vez al mes? Empieza con el ajuste más grueso que cubra tu necesidad.
- Usa los controles visuales: selecciona valores de minuto, hora, día, mes y día de la semana en los menús desplegables. O empieza con un preajuste como "cada hora" o "diario a medianoche" y ajusta.
- Previsualiza las próximas ejecuciones: el generador muestra los próximos 5 horarios de ejecución, lo que te permite confirmar que el horario se dispara cuando esperas.
- Verifica el huso horario: la previsualización debe coincidir con el huso del servidor o planificador que ejecutará la tarea, no con tu hora local.
- Copia la expresión y pégala en tu crontab, YAML de GitHub Actions, regla de AWS EventBridge o el planificador que uses.
- Prueba primero con un intervalo corto antes de fijar el horario final. Un rápido
*/5 * * * *prueba que la tarea se dispara; cuando veas dos o tres ejecuciones, cambia a la expresión real.
Caracteres y operadores especiales
Cron admite un pequeño pero potente conjunto de operadores dentro de cualquier campo.
| Carácter | Significado | Ejemplo |
|---|---|---|
* | Cualquier valor | * * * * * = cada minuto |
*/n | Cada n | */15 * * * * = cada 15 min |
, | Varios valores discretos | 0 8,12,18 * * * = 8h, mediodía, 18h |
- | Rango inclusivo | 0 9-17 * * * = cada hora de 9h a 17h |
n-m/k | Rango con paso | 0 9-17/2 * * * = 9, 11, 13, 15, 17 |
? | Sin valor específico (solo Quartz) | 0 0 ? * MON (planificadores Java) |
L | Último (AWS, Quartz) | L en DoM = último día del mes |
W | Día laborable más cercano (AWS, Quartz) | 15W = día laborable más cercano al 15 |
# | Enésimo día de la semana (AWS, Quartz) | MON#2 = segundo lunes del mes |
@hourly | Atajo | Igual que 0 * * * * |
Vixie cron clásico solo admite las primeras cinco filas. Los operadores avanzados (L, W, #, ?) vienen de Quartz, la biblioteca de planificación Java, y fueron adoptados por AWS EventBridge y unos pocos planificadores cloud más. No son portables, así que no los mezcles con código que tiene que ejecutarse en una caja Linux genérica.
Cron en diferentes plataformas
Cron es una familia de sintaxis relacionadas, no un estándar único. Saber qué dialecto habla tu planificador ahorra horas de depuración.
| Plataforma | Campos | Notas |
|---|---|---|
| Vixie cron (Linux) | 5 | El clásico. */n, rangos, listas, sin operadores avanzados |
| BSD cron | 5 | Como Vixie pero ligeras diferencias de entorno |
| crontab.guru | 5 | Analizador web que refleja la semántica de Vixie |
| GitHub Actions | 5 | Sintaxis Vixie, corre en UTC, resolución mínima 5 minutos |
| GitLab CI | 5 | Sintaxis Vixie, corre en el huso de la instancia |
| AWS EventBridge | 6 | Añade año. Día de la semana usa 1-7 (Dom=1), soporta L/W/# |
| Google Cloud Scheduler | 5 | Sintaxis Vixie más configuración de huso horario |
| Kubernetes CronJob | 5 | Sintaxis Vixie con atajos @ |
| Quartz (Java) | 6 o 7 | Añade segundos al principio y año opcional |
| Timers de systemd | Formato OnCalendar | No es cron, pero resuelve el mismo problema con sintaxis más clara |
Si escribes un horario que tiene que correr en más de una plataforma, atente al subconjunto conservador de 5 campos que todo sistema entiende. Recurre a L, W o # solo cuando sepas que el destino los soporta.
Errores comunes
- Día-del-mes y día-de-la-semana se combinan con O, una expresión como
0 9 15 * 1se dispara cada lunes Y el 15 de cada mes, no solo el 15 cuando cae en lunes. Para intersectar, normalmente necesitas un envoltorio externo o un planificador distinto. - Confusión de huso horario, las crontabs de servidor corren casi siempre en UTC. Si quieres las 9 AM hora del Este, eso es
0 14 * * *UTC en invierno pero0 13 * * *UTC en verano por el horario de verano. Usa un planificador que admita pistas de huso, o normaliza todo a UTC. - Transiciones de horario de verano, las tareas planificadas a las 02:30 hora local pueden ejecutarse dos veces cuando se retrasan los relojes y no ejecutarse cuando se adelantan. Planifica tareas sensibles fuera de la ventana 01:00-03:00 o usa UTC.
- El truco de
MAILTOde Vixie, si tu tarea imprime algo en stdout, Vixie cron envía la salida por correo al usuario propietario de la crontab. En servidores sin relay de correo esto llena/var/spool/mailrápidamente. Redirige la salida a un archivo de log con>>/var/log/myjob.log 2>&1. - El entorno no es tu shell de login, cron corre con un entorno despojado: sin
PATHde tu.bashrc, sin virtualenv, sinnvm. Define las variables que necesites al principio de la crontab o llama a tu script con ruta absoluta. - Los signos de porcentaje necesitan escape, un
%sin escapar en una crontab Vixie se interpreta como un carácter de nueva línea en el comando. Escápalo siempre como\%si tu comando necesita un porcentaje literal, por ejemplo en una invocacióndate +"%Y-%m-%d". - Las tareas largas se solapan, cron no salta una ejecución porque la anterior siga corriendo. Si tu tarea puede tardar más que el intervalo, envuélvela en un archivo de bloqueo (
flock,setlock) o usa un ejecutor que maneje concurrencia. - Desbordamiento en el minuto 59,
*/40 * * * *no se dispara cada 40 minutos. Se dispara en el minuto 0 y 40 de cada hora porque los valores de paso dan la vuelta en los límites del campo. Para intervalos reales de 40 minutos necesitas un planificador más rico. - Olvidar
0en el campo minuto,* 9 * * *corre cada minuto de 09:00 a 09:59, no una vez a las 09:00. El campo minuto necesita un valor explícito si quieres un único disparo por hora. - Cron no es fiable en portátiles, anacron existe por esa razón. Vixie cron no recupera ejecuciones perdidas tras un suspendido, así que un respaldo diario planificado a las 03:00 no correrá si el portátil estaba cerrado a esa hora. Usa anacron, timers de systemd con
Persistent=true, o un plist de launchd en macOS.
Alternativas a cron
Para algunas cargas de trabajo la resolución gruesa por minuto de cron y la falta de contabilidad empiezan a doler. Las mejoras más comunes:
| Herramienta | Fortaleza | Cuándo elegirla |
|---|---|---|
| Timers de systemd | Sintaxis OnCalendar clara, persistente entre reinicios, integra con units | Ya usas systemd y quieres logging más rico |
| Anacron | Recupera ejecuciones perdidas tras suspendido | Portátiles o máquinas que no están siempre encendidas |
| Airflow / Dagster | Dependencias DAG, reintentos, observabilidad | Pipelines de datos multi-paso |
| Temporal | Flujos con estado, garantías exactamente-una-vez | Orquestación de larga duración entre servicios |
| AWS EventBridge | Gestionado, integra con Lambda, S3, SQS | Cualquier cosa cloud-nativa en AWS |
| GitHub Actions | Gratis para repos públicos, corre en runners hospedados | Tareas planificadas adyacentes al CI |
| funciones serverless con triggers cron | Sin servidor que mantener | Tareas ligeras que caben en un Lambda |
Cron sigue siendo la respuesta correcta para la gran mayoría de tareas recurrentes de una sola pieza. Las otras herramientas brillan cuando necesitas estado, reintentos, dependencias o coordinación entre máquinas.
Privacidad y el generador cron
El generador de expresiones cron corre completamente en tu navegador. El horario que construyes, la previsualización de próximas ejecuciones y la expresión copiada nunca tocan nuestros servidores. No hay registro de qué expresiones se generaron, ni telemetría sobre qué preajustes son populares, ni manera de que nadie reconstruya en qué horario estabas trabajando. Las expresiones cron no son datos personales a primera vista, pero el horario de una tarea (una exportación de base de datos nocturna, una ejecución de facturación semanal, una sincronización horaria con un socio) puede revelar mucho sobre cómo opera un negocio. Mantener esa información del lado del cliente evita filtrar accidentalmente patrones de infraestructura a un tercero. Para una tarea tan rutinaria como elegir un horario, el ajuste de privacidad por defecto debe coincidir con la sensibilidad de lo que esos horarios representan.
Preguntas frecuentes
¿Cuál es el formato de una expresión cron?
Una expresión cron estándar tiene 5 campos separados por espacios, que representan minuto (0-59), hora (0-23), día del mes (1-31), mes (1-12) y día de la semana (0-6, donde 0 es domingo). Un asterisco (*) significa «cualquier» valor para ese campo.
¿Qué significa */5 en cron?
La sintaxis */5 significa «cada 5». En el campo minuto, */5 significa cada 5 minutos (0, 5, 10, 15...). En el campo hora, */5 significa cada 5 horas. Funciona en cualquier campo.
¿Las expresiones cron son idénticas en todas las plataformas?
El formato de 5 campos es estándar en el cron de Linux, AWS EventBridge, GitHub Actions y la mayoría de los sistemas de programación. Algunas plataformas añaden un 6.º campo para los segundos o el año. Consulta la documentación de tu plataforma.
¿Cómo programar para el último día de cada mes?
El cron estándar no tiene una palabra clave de «último día». Usa una solución alternativa como una ejecución diaria con una comprobación de fecha en tu script, o usa extensiones propias de la plataforma (AWS EventBridge admite L para «last»).
Why did my cron job not run at the expected time?
The most common cause is timezone confusion. Server cron usually runs in UTC, not your local time. Other causes include the server being asleep at the scheduled minute, the user crontab not being installed, or PATH/environment differences between your shell and cron's stripped-down environment.
What is the difference between 0 in the day-of-week field and 7?
Both 0 and 7 represent Sunday in classic Vixie cron, which uses 0-6 plus an alias for 7. Some implementations (notably AWS EventBridge) use 1-7 with Sunday as 7 and Monday as 1, so always check your platform's documentation before assuming.