Guía

Crontab: ejemplos de programación de tareas en Linux, sintaxis y errores típicos

Actualizado: · Skillaria.Top

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:

ComandoQué hace
crontab -eabrir la tabla propia en el editor (la primera vez pregunta qué editor usar)
crontab -lmostrar la tabla actual
crontab -rborrar la tabla completa, sin confirmación
crontab -i -rborrar con confirmación (Debian/Ubuntu, RHEL)
sudo crontab -u alice -eeditar la tabla de otro usuario
crontab archivoreemplazar 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ácterSignificadoEjemplo
*cualquier valor* * * * * — cada minuto
,lista0 9,18 * * * — a las 9:00 y a las 18:00
-rango0 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ónLínea de crontab
cada minuto* * * * *
cada 5 minutos*/5 * * * *
cada 30 minutos*/30 * * * * o 0,30 * * * *
cada hora, al inicio de la hora0 * * * *
cada 6 horas0 */6 * * *
todos los días a las 3:000 3 * * *
todos los días a las 23:4545 23 * * *
de lunes a viernes a las 9:000 9 * * 1-5
los fines de semana al mediodía0 12 * * 6,0
los lunes a las 8:3030 8 * * 1
el día 1 de cada mes a las 00:000 0 1 * *
una vez por trimestre0 0 1 1,4,7,10 *
una vez al año, el 1 de enero0 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:

AliasEquivalente
@rebootuna vez al iniciar el demonio cron (tras arrancar el sistema)
@hourly0 * * * *
@daily / @midnight0 0 * * *
@weekly0 0 * * 0
@monthly0 0 1 * *
@yearly / @annually0 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 lanza run-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.

Aprende este tema en vídeo

Este tema se explica a fondo y con práctica en el curso «Linux: с нуля до уверенного администрирования».

Ir al curso