Toolbit
Guías

Crontab: 20 ejemplos reales explicados

Veinte expresiones cron para tareas reales, de cada 5 minutos a fin de mes, con las trampas más comunes: la regla O entre días, los % sin escapar y el horario de verano.

Por Javier VallejoPublicado el 7 min de lectura

Cómo leer una línea de crontab

Una entrada de crontab tiene cinco campos de tiempo seguidos del comando a ejecutar. Cada campo restringe cuándo se dispara la tarea, y la tarea corre en cada minuto en que todos los campos coinciden (con una excepción importante entre día del mes y día de la semana, que se explica más abajo):

┌───────── 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 son domingo)
│ │ │ │ │
* * * * *  comando

Cada campo acepta cuatro formas de escribir valores, que se pueden combinar:

SintaxisSignificadoEjemplo en el campo hora
*cualquier valortodas las horas
a,b,clista8,12,18 → a las 8, 12 y 18
a-brango inclusivo9-17 → de 9 a 17
*/n o a-b/npaso*/6 → 0, 6, 12, 18

Los 20 ejemplos de esta guía usan solo esa sintaxis numérica, que es la que entienden todas las implementaciones (Vixie cron, cronie, BusyBox crond, Kubernetes CronJob). Cada expresión enlaza al explicador de cron con el valor ya cargado, para ver su traducción y las próximas ejecuciones.

Frecuencias cortas

1. */5 * * * *: cada 5 minutos. El caso típico de un chequeo de salud o de una cola que se procesa por lotes. */5 en el campo de minutos significa "desde 0, cada 5": 0, 5, 10… 55. No significa "5 minutos después de la última ejecución": si la tarea tarda 7 minutos, la siguiente arranca igual en el próximo múltiplo de 5.

2. 0,30 * * * *: cada media hora, en punto y a la media. Equivale a */30 * * * *, pero la lista deja explícitos los minutos exactos, lo que facilita leerlo meses después.

3. 0 * * * *: al comienzo de cada hora. Es lo mismo que la macro @hourly. Un error común es escribir * * * * * pensando en "cada hora": eso ejecuta la tarea cada minuto, 1440 veces por día.

4. 0 */6 * * *: cada 6 horas (00:00, 06:00, 12:00, 18:00). Útil para renovar certificados, sincronizar inventarios o refrescar cachés que no necesitan estar al minuto. El 0 en minutos es imprescindible: con * */6 * * * la tarea correría los 60 minutos de cada una de esas horas.

Tareas diarias

5. 30 2 * * *: todos los días a las 02:30. El horario clásico de respaldos: poca carga y lejos del cambio de fecha. Tiene una trampa con el horario de verano que se explica al final.

6. 5 0 * * *: todos los días a las 00:05. Cinco minutos después de medianoche, para tareas que procesan "el día anterior" (reportes, rotación de logs) y necesitan que el día ya haya cerrado. Programarlas a las 0 0 exactas suele coincidir con otras diez tareas que alguien más puso a medianoche.

7. 0 8,12,18 * * *: tres veces al día, a las 8, 12 y 18. Por ejemplo, un resumen de alertas pendientes al inicio, mitad y final de la jornada.

Horario laboral

8. 0 9-18 * * 1-5: cada hora en punto de 9 a 18, de lunes a viernes. Los rangos son inclusivos: 9-18 incluye las 18:00. Si la última ejecución debe ser a las 17:00, el rango es 9-17.

9. */15 9-17 * * 1-5: cada 15 minutos en horario laboral. La última ejecución del día es a las 17:45, porque el campo de hora habilita toda la hora 17 y el campo de minutos la recorre completa.

10. 0 22 * * 1-5: días hábiles a las 22:00. Para procesos nocturnos que no hace falta correr el fin de semana, como compilar el reporte de ventas del día.

11. */10 * * * 0,6: cada 10 minutos, solo sábados y domingos. El inverso del anterior: monitoreo más frecuente cuando no hay nadie mirando los paneles.

Tareas semanales

12. 0 0 * * 0: domingos a medianoche. Es la macro @weekly. El domingo puede escribirse como 0 o como 7; 0 es la forma más portable.

13. 0 8 * * 1: lunes a las 08:00. El horario natural para enviar un informe semanal que alguien va a leer al empezar la semana.

14. 0 3 * * 6: sábados a las 03:00. Una ventana de mantenimiento semanal: reindexar bases de datos, limpiar imágenes de contenedores viejas, ejecutar fstrim.

Tareas mensuales y anuales

15. 0 0 1 * *: el día 1 de cada mes a medianoche. Es la macro @monthly. Típico para cierres de facturación o para archivar los logs del mes anterior.

16. 0 6 1,15 * *: los días 1 y 15 a las 06:00. Una frecuencia quincenal aproximada. No equivale a "cada 15 días": entre el 15 y el 1 del mes siguiente pueden pasar entre 14 y 17 días según el mes.

17. 15 14 1 * *: el día 1 de cada mes a las 14:15. Es el ejemplo que trae la propia página de manual crontab(5), y sirve para recordar el orden de los campos: primero el minuto, después la hora.

18. 0 0 1 1,4,7,10 *: el primer día de cada trimestre. Enero, abril, julio y octubre. También se puede escribir 0 0 1 */3 *, porque el paso arranca en el mínimo del campo (1) y produce 1, 4, 7 y 10.

Dos casos con trampa

19. 0 4 8-14 * 1: NO es "el segundo lunes del mes". Parece lógico, porque el segundo lunes siempre cae entre el 8 y el 14. Pero cuando día del mes y día de la semana están ambos restringidos, cron los combina con O, no con Y: la tarea corre todos los días del 8 al 14 y además todos los lunes. La forma correcta es restringir solo el día del mes y verificar el día de la semana en el comando:

0 4 8-14 * *  [ "$(date +\%u)" = 1 ] && /usr/local/bin/tarea

Los % van escapados con \ porque en crontab un % sin escapar se interpreta como salto de línea (todo lo que sigue se pasa al comando como entrada estándar).

20. 0 23 28-31 * * + verificación: el último día del mes. Cron no tiene una forma estándar de decir "último día" (algunas implementaciones aceptan L, pero no es portable). El truco es ejecutar los días 28 a 31 y comprobar si mañana es día 1:

0 23 28-31 * *  [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/cierre-mensual

date -d tomorrow es sintaxis de GNU date; en BSD y macOS el equivalente es date -v+1d.

Lo que el crontab no dice pero importa

  • El entorno es mínimo. Cron ejecuta con un PATH reducido (a menudo solo /usr/bin:/bin) y con /bin/sh, no con la shell de la sesión. Conviene usar rutas absolutas o definir PATH= al comienzo del crontab.
  • La salida va por correo o se pierde. Si no hay un MTA configurado, todo lo que el comando escriba se descarta. Redirigir explícitamente evita sorpresas: >> /var/log/tarea.log 2>&1.
  • Las ejecuciones pueden superponerse. Si una tarea cada 5 minutos a veces tarda 8, habrá dos copias corriendo al mismo tiempo. flock -n /tmp/tarea.lock comando hace que la segunda copia salga sin ejecutar.
  • La zona horaria es la del sistema. Un servidor en UTC ejecuta 0 9 * * * a las 9 UTC, no a las 9 locales. Cronie permite fijar otra con la variable CRON_TZ. Para entender las diferencias entre hora local, UTC y timestamps, ver Timestamps Unix y zonas horarias: cómo manejar fechas sin errores.
  • El horario de verano mueve las cosas. En el día del cambio, una hora local no existe o se repite. Cronie y Vixie cron intentan compensar las tareas a hora fija, pero una tarea a las 02:30 puede quedar desplazada ese día. Las tareas críticas conviene programarlas fuera de la franja de 01:00 a 03:00, o correr el servidor en UTC.
  • Las macros ahorran caracteres, no claridad. @daily, @weekly, @monthly y @yearly equivalen a 0 0 * * *, 0 0 * * 0, 0 0 1 * * y 0 0 1 1 *. @reboot (ejecutar al arrancar) existe en Vixie cron y cronie, pero no es un horario, así que no tiene "próximas ejecuciones" que calcular.

Resumen

Casi cualquier horario real entra en cinco campos con listas, rangos y pasos. Los errores más caros vienen siempre de los mismos lugares: un * en minutos que convierte "cada hora" en "cada minuto", la regla O entre día del mes y día de la semana, los % sin escapar y un entorno distinto al de la terminal. Antes de instalar una expresión en producción, vale la pena pegarla en el explicador y revisar la lista de próximas ejecuciones: es la forma más rápida de detectar cualquiera de estos errores.

Herramientas usadas en esta guía

Guías relacionadas