Cómo programar tareas con cron para que tus scripts de Bash se ejecuten solos: cómo se lee una línea del crontab, cómo instalarlo y revisarlo, por qué un script que funciona en la terminal falla en cron, cómo guardar un registro y cómo evitar que dos ejecuciones se pisen con flock.
También te puede interesar
Qué es cron y cómo se lee una línea
cron es el servicio de Linux que ejecuta órdenes a horas fijas: cada noche, cada lunes, cada cuarto de hora. Cada usuario tiene su propia lista de tareas, el crontab, y cada línea de esa lista tiene cinco campos de tiempo seguidos de la orden:
- CampoValoresEjemplo
- Minuto0-59
30: en el minuto 30 - Hora0-23
2: a las 2 de la madrugada - Día del mes1-31
1: el día 1 - Mes1-12
*: todos los meses - Día de la semana0-7 (0 y 7 son domingo)
1-5: de lunes a viernes
Un * significa «todos», */15 «cada 15», 1-5 un rango y 1,15 una lista. Así se leen las líneas más típicas:
- LíneaCuándo se ejecuta
30 2 * * *Todos los días a las 2:30*/15 * * * *Cada 15 minutos0 9 * * 1-5De lunes a viernes a las 9:000 0 1 * *El día 1 de cada mes a medianoche@rebootUna vez, al arrancar el equipo
Si tienes dudas con una expresión, pégala en nuestro traductor de cron a español, que te dice qué significa y cuándo serán las próximas ejecuciones.
Ver, instalar y quitar tu crontab
La orden es crontab: -l lo muestra, -e lo abre en el editor y -r lo borra entero (sin preguntar, así que cuidado con confundirla con la -e, que está al lado en el teclado). También se puede instalar desde un archivo, que es lo más cómodo para guardarlo en un repositorio:
terminal$ crontab -l no crontab for ana $ crontab tareas.cron $ crontab -l # m h dom mes dow orden 30 2 * * * /home/ana/bin/respaldo.sh /home/ana/documentos /mnt/copias 14 >> /home/ana/respaldo.log 2>&1 */15 * * * * /home/ana/bin/comprobar-web.sh 0 9 * * 1-5 /home/ana/bin/informe-diario.sh $ crontab -r $ crontab -l no crontab for ana
cron y viene instalado; compruébalo con systemctl status cron. En WSL no arranca solo: hay que activarlo con sudo service cron start o configurar systemd. En macOS cron sigue funcionando, aunque Apple prefiere launchd.El error más común: el entorno de cron
Un script que funciona perfectamente desde la terminal falla en cron sin decir nada. Casi siempre es por lo mismo: cron no carga tu .bashrc ni tu perfil. Ejecuta las órdenes con /bin/sh, en tu carpeta personal y con un PATH mínimo (/usr/bin:/bin). Se puede imitar con env -i, que borra el entorno, para probar el script tal como lo verá cron antes de programarlo:
#!/usr/bin/env bash # Una orden propia en ~/proyecto/bin y la carpeta añadida al PATH, como en un .bashrc export PATH="$PWD/bin:$PATH" chmod +x bin/saludar echo "--- Desde la terminal" saludar echo "PATH tiene $(tr ':' '\n' <<< "$PATH" | wc -l) carpetas" echo "--- Como lo ejecutaría cron" env -i HOME="$HOME" LOGNAME="$LOGNAME" SHELL=/bin/sh PATH=/usr/bin:/bin /bin/sh -c 'env | sort; saludar' echo "código de salida: $?"
salida--- Desde la terminal Hola desde ~/bin PATH tiene 4 carpetas --- Como lo ejecutaría cron HOME=/home/ana LOGNAME=ana PATH=/usr/bin:/bin PWD=/home/ana/proyecto SHELL=/bin/sh /bin/sh: 1: saludar: not found código de salida: 127
Las variables que ve cron son solo esas cuatro, y saludar ya no se encuentra. Tres formas de evitarlo, de mejor a peor: usar rutas absolutas en el script (/home/ana/bin/saludar), definir PATH al principio del script o del crontab (una línea PATH=/usr/local/bin:/usr/bin:/bin antes de las tareas), o cargar el perfil a mano, que arrastra cosas que no hacen falta.
- Problema en cronPor quéSolución
command not foundEl PATH es solo/usr/bin:/binRutas absolutas oPATH=en el crontab- No encuentra sus archivosSe ejecuta en tu carpeta personal, no en la del script
cd "$(dirname "$0")"al principio, o rutas absolutas - Falla un
[[ ]]o un arrayLa orden se interpreta con/bin/sh(dash)Shebang#!/usr/bin/env bashy permiso de ejecución - La orden se corta en un
%En el crontab,%significa salto de líneaEscríbelo como\%:date +\%F - No pasa nada y no hay rastroLa salida se envía por correo local, si lo hayRedirige:
>> ~/tarea.log 2>&1
Guardar un registro
Si no rediriges la salida, cron intenta mandarla por correo al usuario, y en la mayoría de los servidores ese correo no llega a ninguna parte. Redirige siempre la salida y los errores a un archivo, y pon la fecha en cada línea para saber cuándo pasó cada cosa. Este envoltorio lo hace dentro del propio script con exec, que redirige todo lo que venga después:
#!/usr/bin/env bash
set -euo pipefail
log="$HOME/tarea.log"
exec >> "$log" 2>&1 # a partir de aquí, todo va al registro
anotar() { printf '%s %s\n' "$(date -u -d "${AHORA:-now}" '+%F %T')" "$*"; }
anotar "inicio"
anotar "procesados 42 archivos"
ls /carpeta-que-no-existe || anotar "aviso: no se pudo listar la carpeta"
anotar "fin"Al ejecutarlo no se ve nada en la pantalla: todo ha ido al registro. (La variable AHORA solo sirve para fijar la hora en esta prueba; sin ella, cada línea lleva la hora real.)
terminal$ AHORA='2026-10-30 02:30:00' bash registro.sh $ cat ~/tarea.log 2026-10-30 02:30:00 inicio 2026-10-30 02:30:00 procesados 42 archivos ls: cannot access '/carpeta-que-no-existe': No such file or directory 2026-10-30 02:30:00 aviso: no se pudo listar la carpeta 2026-10-30 02:30:00 fin
Que no se solapen dos ejecuciones: flock
Si una tarea programada cada 15 minutos tarda 20 un día, cron lanzará la siguiente con la primera aún en marcha, y las dos pisarán los mismos archivos. flock lo evita: toma un cerrojo sobre un archivo y, con -n, si ya lo tiene otro proceso, se rinde al momento en lugar de esperar:
#!/usr/bin/env bash
tarea() {
exec 9> "$HOME/tarea.lock"
if ! flock -n 9; then
echo "[$1] ya hay otra ejecución en marcha; salgo sin hacer nada"
return 1
fi
echo "[$1] trabajando..."
sleep 1
echo "[$1] terminada"
}
tarea primera &
sleep 0.3
tarea segunda
waitsalida[primera] trabajando... [segunda] ya hay otra ejecución en marcha; salgo sin hacer nada [primera] terminada
El cerrojo se suelta solo cuando termina el proceso que lo tiene, aunque falle o lo maten, así que no quedan cerrojos «olvidados». En el propio crontab también se puede usar sin tocar el script: */15 * * * * flock -n /tmp/comprobar.lock /home/ana/bin/comprobar-web.sh.
Alternativas a cron
En los sistemas con systemd (Ubuntu, Debian, Fedora…) existen los timers de systemd, que registran cada ejecución en el diario del sistema (journalctl), pueden recuperar las ejecuciones perdidas si el equipo estaba apagado y evitan los solapamientos por sí mismos. Son más verbosos de configurar, con dos archivos por tarea, pero para un servidor merecen la pena. En macOS el equivalente es launchd. Para una tarea personal sencilla, cron sigue siendo lo más rápido.
Todos los scripts de esta página se ejecutaron con Bash 5.3 en Ubuntu 26.04, en un contenedor limpio sin acceso a la red, y pasaron ShellCheck 0.11 sin avisos antes de publicarla; las salidas están copiadas de esa ejecución.