Crontab: ejemplos de programación de tareas en Linux, sintaxis y errores típicos
Crontab es una tabla de programación según la cual el demonio cron ejecuta comandos: cada línea tiene cinco campos de tiempo (minuto, hora, día del mes, mes, día de la semana) y el comando, por ejemplo */5 * * * * /opt/backup.sh ejecuta el script cada 5 minutos. La tabla se edita con crontab -e, y la mayoría de problemas se deben al entorno reducido de cron: indique rutas completas y redirija la salida a un registro.
Cron es el planificador de tareas estándar de Linux: el demonio cron lee cada minuto las tablas de programación (crontab) y lanza los comandos cuyo momento ha llegado. Así se hacen las copias de seguridad nocturnas, se limpian archivos temporales, se renuevan certificados y se envían informes. A continuación tiene la sintaxis, ejemplos de crontab para los casos típicos y un análisis de los errores que hacen que una tarea no se ejecute «en silencio».
Cómo abrir y editar el crontab
Cada usuario tiene su propia tabla. Se trabaja con ella mediante el comando crontab, y no editando directamente los archivos de /var/spool/cron:
| Comando | Qué hace |
|---|---|
crontab -e | abrir la tabla propia en el editor (la primera vez pregunta qué editor usar) |
crontab -l | mostrar la tabla actual |
crontab -r | borrar la tabla completa, sin confirmación |
crontab -i -r | borrar con confirmación (Debian/Ubuntu, RHEL) |
sudo crontab -u alice -e | editar la tabla de otro usuario |
crontab archivo | reemplazar la tabla por el contenido de un archivo |
Tras guardar con crontab -e, la herramienta comprueba la sintaxis y escribe crontab: installing new crontab. Si hay un error en alguna línea, verá errors in crontab file, can't install y se le ofrecerá volver a editar. No hace falta reiniciar el demonio: los cambios se aplican solos.
Tenga cuidado con -r: las teclas e y r están juntas en el teclado, y no hay copia de seguridad de la tabla. Buena costumbre: guardar una copia.
crontab -l > ~/crontab.bak
# restaurar
crontab ~/crontab.bak
Sintaxis del crontab: cinco campos de tiempo
Cada línea de tarea tiene este aspecto:
# ┌───────── minuto (0–59)
# │ ┌─────── hora (0–23)
# │ │ ┌───── día del mes (1–31)
# │ │ │ ┌─── mes (1–12 o jan–dec)
# │ │ │ │ ┌─ día de la semana (0–7 o sun–sat; 0 y 7 — domingo)
# │ │ │ │ │
* * * * * comando
En cada campo se pueden usar caracteres especiales:
| Carácter | Significado | Ejemplo |
|---|---|---|
* | cualquier valor | * * * * * — cada minuto |
, | lista | 0 9,18 * * * — a las 9:00 y a las 18:00 |
- | rango | 0 9-18 * * * — cada hora de 9 a 18 |
/ | paso | */15 * * * * — cada 15 minutos |
El paso puede combinarse con un rango: 0 8-20/2 * * * — cada dos horas de 8 a 20 (8, 10, …, 20). La hora se toma de la zona horaria del sistema; compruébela con timedatectl.
Ejemplos de crontab para cada día
| Programación | Línea de crontab |
|---|---|
| cada minuto | * * * * * |
| cada 5 minutos | */5 * * * * |
| cada 30 minutos | */30 * * * * o 0,30 * * * * |
| cada hora, al inicio de la hora | 0 * * * * |
| cada 6 horas | 0 */6 * * * |
| todos los días a las 3:00 | 0 3 * * * |
| todos los días a las 23:45 | 45 23 * * * |
| de lunes a viernes a las 9:00 | 0 9 * * 1-5 |
| los fines de semana al mediodía | 0 12 * * 6,0 |
| los lunes a las 8:30 | 30 8 * * 1 |
| el día 1 de cada mes a las 00:00 | 0 0 1 * * |
| una vez por trimestre | 0 0 1 1,4,7,10 * |
| una vez al año, el 1 de enero | 0 0 1 1 * |
| cada 10 minutos en horario laboral | */10 9-18 * * 1-5 |
Una línea de tarea completa es la programación más el comando:
# copia de seguridad de la base de datos cada noche a las 3:00
0 3 * * * /usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1
# limpieza de archivos temporales de más de 7 días los domingos
0 4 * * 0 /usr/bin/find /tmp/app -type f -mtime +7 -delete
# comprobación del sitio cada 5 minutos
*/5 * * * * /usr/bin/curl -fsS https://example.com/health > /dev/null || /usr/local/bin/alert.sh
Cadenas especiales @reboot, @daily y otras
En lugar de los cinco campos se puede escribir un alias corto:
| Alias | Equivalente |
|---|---|
@reboot | una vez al iniciar el demonio cron (tras arrancar el sistema) |
@hourly | 0 * * * * |
@daily / @midnight | 0 0 * * * |
@weekly | 0 0 * * 0 |
@monthly | 0 0 1 * * |
@yearly / @annually | 0 0 1 1 * |
@reboot /home/alice/bin/start-tunnel.sh >> /home/alice/tunnel.log 2>&1
Para servicios que deben funcionar de forma permanente y reiniciarse si se caen, @reboot es una solución débil: mejor cree una unidad de systemd con Restart=on-failure.
Cómo ejecutar una tarea cada N segundos
La unidad mínima de cron es un minuto. Si hace falta con más frecuencia, hay dos recursos. El primero, varias líneas con un desfase mediante sleep:
* * * * * /opt/check.sh
* * * * * sleep 30; /opt/check.sh
El segundo, más correcto, es un temporizador de systemd con OnUnitActiveSec=30s. Si una tarea se ejecuta más de una vez por minuto, normalmente ya es trabajo para un demonio o un temporizador, no para cron.
Crontab del sistema: /etc/crontab y /etc/cron.d
Además de las tablas de usuario existen las del sistema. Su formato es distinto: entre la hora y el comando va el nombre de usuario con cuyos permisos se ejecuta el comando.
# /etc/cron.d/certbot-renew
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root certbot renew --quiet
Dónde está cada cosa:
/etc/crontab— la tabla principal del sistema; en Debian/Ubuntu desde ella se lanzan los directorios de abajo./etc/cron.d/— archivos independientes con tareas; es cómodo que los instalen los paquetes o Ansible./etc/cron.hourly/,cron.daily/,cron.weekly/,cron.monthly/— aquí se colocan scripts ejecutables sin horario; los lanzarun-parts(o anacron).
Trampa de run-parts: en Debian y Ubuntu omite los archivos cuyo nombre contiene un punto. Un script backup.sh en /etc/cron.daily/ no se ejecutará: llámelo backup. Para comprobar qué se ejecutaría, use run-parts --test /etc/cron.daily.
Los archivos de /etc/cron.d/ deben pertenecer a root, no tener permiso de escritura para el grupo ni para otros, y terminar con un salto de línea; si no, cron los ignorará.
Entorno de cron: PATH, SHELL y variables
La causa principal de la frase «en la terminal funciona, en cron no» es el entorno. Cron ejecuta los comandos con /bin/sh, sin su .bashrc ni su .profile, y con un PATH mínimo (normalmente /usr/bin:/bin). Por eso docker, node o php instalados en /usr/local/bin pueden simplemente no encontrarse.
Las variables se pueden definir al principio de la tabla:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com
CRON_TZ=Europe/Moscow
0 6 * * * cd /srv/app && ./report.sh
MAILTO— a dónde enviar la salida de la tarea;MAILTO=""desactiva los correos.CRON_TZ— zona horaria de la programación (la admite cronie en RHEL/Fedora; en la versión de cron de Debian esta variable no funciona).- En los valores de las variables no hay sustituciones como
$HOME/bin: escriba las rutas completas.
La opción más fiable es indicar en la tarea rutas absolutas a todos los programas y archivos, y poner en la primera línea de los scripts el shebang: #!/bin/bash.
Dónde ver los registros de cron
Cron registra en el diario el hecho de que la tarea se ha lanzado, pero no su salida:
# Debian/Ubuntu
grep CRON /var/log/syslog
# mediante systemd-journald
journalctl -u cron --since today # Debian/Ubuntu
journalctl -u crond --since today # RHEL, Fedora, Rocky
# RHEL sin journald
tail -f /var/log/cron
La línea de arranque tiene un aspecto parecido a este:
Oct 14 03:00:01 web1 CRON[21544]: (root) CMD (/usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1)
Para ver qué escribió la tarea y con qué error falló, redirija tanto stdout como stderr a un archivo: >> /var/log/job.log 2>&1. Sin eso, la salida se envía por correo local, y si no hay agente de correo instalado, se pierde (en el diario aparecerá No MTA installed, discarding output).
Por qué cron no ejecuta la tarea: errores típicos
El comando no se encuentra
Síntoma: en el registro de la tarea aparece command not found. Causa: un PATH reducido. Solución: la ruta completa al programa (which docker le dirá cuál es) o una línea PATH= al principio de la tabla.
El símbolo de porcentaje en el comando
En crontab el carácter % significa salto de línea: todo lo que va después del primer % se pasa al comando por la entrada estándar. Por eso falla la línea clásica con una fecha en el nombre del archivo:
# incorrecto — el comando se corta en el primer %
0 2 * * * tar czf /backup/site-$(date +%F).tar.gz /var/www
# correcto — escapar
0 2 * * * tar czf /backup/site-$(date +\%F).tar.gz /var/www
Más sencillo aún: pasar la lógica a un script, donde el % no necesita escaparse.
El script no es ejecutable o tiene saltos de línea incorrectos
El error Permission denied significa que el archivo no tiene el bit x: ejecute chmod +x script.sh o lance el script de forma explícita, /bin/bash /opt/script.sh. Si el script se escribió en Windows, los saltos de línea CRLF provocan un error extraño /bin/bash^M: bad interpreter; se corrige con sed -i 's/\r$//' script.sh o con dos2unix.
Rutas relativas y directorio de trabajo
La tarea arranca en el directorio personal del usuario. Si el script lee ./config.ini, lo buscará en ~. Anteponga cd /srv/app && al comando o use rutas absolutas dentro del script.
Día del mes y día de la semana a la vez
Si se indican ambos campos, cron se ejecuta cuando coincide cualquiera de ellos, no los dos a la vez. La línea 0 9 13 * 5 se ejecutará el día 13 del mes y todos los viernes, no solo el viernes 13. La condición correcta se comprueba dentro del comando:
0 9 13 * * [ "$(date +\%u)" = 5 ] && /opt/friday13.sh
Las tareas se solapan
Si la copia de seguridad tarda más que el intervalo, la siguiente ejecución arranca encima de la anterior. La protección es un bloqueo con flock:
*/10 * * * * /usr/bin/flock -n /tmp/sync.lock /opt/sync.sh
Con la opción -n, la segunda instancia termina de inmediato si la primera sigue en marcha.
El demonio cron no está en marcha
Compruebe con systemctl status cron (en RHEL, crond). En las imágenes mínimas, por ejemplo en contenedores de Docker, el demonio cron no existe: las tareas del crontab simplemente no tienen quien las ejecute.
Cómo depurar una tarea de cron
Ejecute el comando en un entorno lo más parecido posible al de cron:
env -i SHELL=/bin/sh PATH=/usr/bin:/bin HOME=$HOME /bin/sh -c '/opt/backup.sh'
Si aquí aparece un error, también aparecerá en cron. Para pruebas, programe temporalmente * * * * *, redirija la salida a un archivo y sígalo con tail -f. Para comprobar la programación en sí ayudan los calculadores en línea de expresiones de cron, pero la última palabra la tiene el registro del sistema.
Quién puede usar cron: cron.allow y cron.deny
El acceso se restringe con los archivos /etc/cron.allow y /etc/cron.deny. Si existe cron.allow, el crontab está disponible solo para los usuarios que aparecen en él. Si no existe, pero sí cron.deny, está disponible para todos excepto los listados. Un usuario bloqueado que ejecute crontab -e recibirá el mensaje You (bob) are not allowed to use this program.
Resumen
Un crontab son líneas con cinco campos de tiempo y un comando: */5 * * * * — cada 5 minutos, 0 3 * * * — cada noche, 0 9 * * 1-5 — de lunes a viernes. Edite la tabla con crontab -e, use rutas absolutas, escape los %, escriba la salida en un registro y proteja las tareas largas con flock. Con estos ejemplos de crontab se cubren la mayoría de las tareas de servidor, y la automatización y la programación de tareas se practican en el curso de Linux.
Preguntas frecuentes
¿En qué se diferencia cron de anacron?
Cron ejecuta las tareas a la hora exacta y se las salta si el equipo estaba apagado. Anacron garantiza que las tareas diarias, semanales y mensuales se completen tras el encendido, por lo que es adecuado para portátiles y equipos de escritorio.
¿Qué es mejor: cron o los temporizadores de systemd?
Cron es más sencillo y está prácticamente en todas partes. Los temporizadores de systemd ofrecen registros en journalctl, dependencias, limitación de recursos y la opción Persistent=true para las ejecuciones omitidas, por eso en los servidores modernos se eligen cada vez más para tareas importantes.
¿Dónde se guarda físicamente el crontab de un usuario?
En Debian y Ubuntu, en /var/spool/cron/crontabs/nombre; en RHEL y Fedora, en /var/spool/cron/nombre. No conviene editar estos archivos directamente: use crontab -e.
¿Cómo desactivar temporalmente una tarea del crontab?
Comente la línea con el símbolo # al principio mediante crontab -e. Para desactivar todas las tareas de un usuario, guarde la tabla en un archivo con crontab -l y después bórrela con crontab -r.
¿Cómo ejecutar una tarea el último día del mes?
No hay un campo específico para ello. Programe la tarea los días 28 a 31 y compruebe que mañana es día 1: 0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && /opt/job.sh.
Este tema se explica a fondo y con práctica en el curso «Linux: с нуля до уверенного администрирования».
Ir al curso