Saltar al contenido
GEEKnodes

Raspberry Pi

Cron en Raspberry Pi: programar tareas automáticas con crontab

Programa tareas en la Raspberry Pi con cron: sintaxis de 5 campos, crontab -e, @reboot, rutas absolutas, logs con journalctl y cuándo usar un timer de systemd.

Copias nocturnas, un script que lee un sensor cada 5 minutos o un reinicio semanal: todo eso se programa con cron. El problema es que un script que funciona perfectamente en la terminal a menudo falla en silencio cuando lo lanza cron. Aquí verás la sintaxis, por qué pasa eso y cómo comprobar si la tarea se ejecutó de verdad.

En resumen

  • Cada línea del crontab tiene 5 campos de tiempo (minuto, hora, día del mes, mes, día de la semana) y después el comando.
  • Cron arranca los comandos con un entorno mínimo: usa siempre rutas absolutas y redirige la salida a un log.
  • En Raspberry Pi OS Bookworm los registros de cron están en el journal: se consultan con journalctl -u cron.

Todo lo que sigue vale para Raspberry Pi OS Bookworm, tanto Lite como con escritorio. Cron viene instalado y activo de serie.

Cómo se lee una línea de crontab

Una tarea es una línea con este formato:

minuto  hora  día-del-mes  mes  día-de-la-semana  comando
Anatomía de una línea de crontab: cinco campos de tiempo minuto, hora, día del mes, mes y día de la semana, seguidos del comando
Cinco campos de tiempo y, después, el comando que se ejecuta.
CampoValoresNotas
Minuto0–59
Hora0–23Formato 24 h, hora local del sistema
Día del mes1–31
Mes1–12También jan, feb…
Día de la semana0–70 y 7 son domingo; también mon, tue…

En cada campo puedes usar:

  • * → cualquier valor.
  • , → lista: 1,15 es «el 1 y el 15».
  • - → rango: 1-5 es «de lunes a viernes».
  • / → intervalo: */10 es «cada 10».

Tabla de ejemplos

ExpresiónCuándo se ejecuta
*/5 * * * *Cada 5 minutos
0 * * * *Al principio de cada hora
30 3 * * *Todos los días a las 03:30
0 8 * * 1-5De lunes a viernes a las 08:00
0 0 1 * *El día 1 de cada mes a medianoche
15 4 * * 0Los domingos a las 04:15
0 9,21 * * *A las 09:00 y a las 21:00
@rebootUna vez, al arrancar el sistema
@dailyEquivale a 0 0 * * *
@weeklyEquivale a 0 0 * * 0

Un detalle que confunde: si restringes a la vez el día del mes y el día de la semana, cron ejecuta la tarea cuando se cumple cualquiera de los dos, no ambos. 0 12 13 * 5 se ejecuta todos los días 13 y todos los viernes, no solo los viernes 13.

Editar el crontab paso a paso

Cada usuario tiene su propio crontab. Las tareas se ejecutan con los permisos de ese usuario.

  1. Abre tu crontab:
crontab -e
  1. La primera vez te pide un editor. Si no sabes cuál elegir, nano es el más sencillo.
  2. Añade la tarea al final del archivo, por ejemplo:
*/5 * * * * /usr/bin/python3 /home/pi/scripts/sensor.py >> /home/pi/logs/sensor.log 2>&1
  1. Guarda y cierra (en nano: Ctrl+O, Intro, Ctrl+X). Verás el mensaje crontab: installing new crontab. No hace falta reiniciar nada.
  2. Comprueba lo que hay instalado:
crontab -l

Para tareas que necesitan permisos de administrador, usa el crontab de root con sudo crontab -e. Es mejor que poner sudo dentro de tu crontab, porque ahí no hay nadie para escribir la contraseña.

Ojo con crontab -r: borra el crontab entero sin preguntar. La r está justo al lado de la e en el teclado.

El entorno mínimo: por qué tu script falla en cron

Cuando abres una terminal, tu shell carga .bashrc, el PATH completo, tus variables y el directorio actual. Cron no carga nada de eso. Arranca los comandos con /bin/sh, un PATH reducido (normalmente solo /usr/bin:/bin) y el directorio personal como directorio de trabajo.

Comparación entre el entorno completo de la terminal y el entorno mínimo de cron, con PATH reducido a /usr/bin y /bin
Cron no carga tu .bashrc: usa rutas absolutas para todo.

Consecuencias prácticas:

  • Un comando que está en /usr/local/bin o en ~/.local/bin no se encuentra.
  • Un script que abre datos.csv sin ruta lo busca en tu carpeta personal, no junto al script.
  • Si usas un entorno virtual de Python, cron no lo activa.

La solución es ser explícito:

*/10 * * * * /home/pi/env/bin/python /home/pi/scripts/lectura.py >> /home/pi/logs/lectura.log 2>&1

Llamar directamente al python de dentro del entorno virtual equivale a activarlo. Si necesitas variables, puedes declararlas al principio del crontab:

PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash

Para saber qué ruta tiene un programa, usa which:

which rsync

El símbolo % es especial

En un crontab, % significa salto de línea. Un comando como date +%Y-%m-%d se rompe. Escápalo con barra invertida: date +\%Y-\%m-\%d. Otra opción más limpia es meter la lógica en un script y llamar solo al script.

Redirigir la salida a un log

Por defecto, cron intenta enviar por correo lo que imprime el comando. Raspberry Pi OS no trae servidor de correo, así que esa salida se pierde y en el journal aparece un aviso del tipo «No MTA installed, discarding output». Si el script falla, no te enteras.

Por eso conviene terminar cada línea con una redirección:

Final de la líneaQué hace
>> /ruta/log 2>&1Añade salida normal y errores al log
> /ruta/log 2>&1Igual, pero sobrescribe el log en cada ejecución
> /dev/null 2>&1Descarta todo (solo si ya sabes que funciona)

La carpeta del log tiene que existir antes; cron no la crea. Y un log con >> crece sin fin: si la tarea es frecuente, vacíalo de vez en cuando o usa logrotate.

@reboot: tareas al arrancar

@reboot lanza el comando una vez cuando arranca el servicio cron:

@reboot sleep 30 && /home/pi/scripts/inicio.sh >> /home/pi/logs/inicio.log 2>&1

El sleep 30 no es decorativo. Cron arranca pronto, y en ese momento la red o un disco USB pueden no estar listos todavía. Si tu script depende de ellos, espera o, mejor, usa un servicio de systemd con dependencias (más abajo).

Ver si una tarea se ejecutó

En Bookworm no existe /var/log/syslog por defecto: los registros van al journal de systemd. Para ver la actividad de cron:

journalctl -u cron --since today

Cada ejecución aparece como una línea con CMD y el comando lanzado. Para seguirlo en directo mientras esperas a que toque la tarea:

journalctl -u cron -f

Si la línea CMD aparece pero el resultado no es el esperado, el problema está en el script: mira tu log. Si no aparece, revisa la sintaxis con crontab -l y que la hora del sistema sea correcta con timedatectl. La Raspberry Pi no tiene reloj con batería en la mayoría de modelos y toma la hora de la red al arrancar.

Cuándo usar un timer de systemd

Cron es perfecto para tareas sencillas. Un timer de systemd compensa cuando necesitas más control:

NecesidadCronTimer de systemd
Sintaxis rápida en una líneaSíNo: dos archivos
Recuperar ejecuciones perdidas con la Pi apagadaNoSí, con Persistent=true
Esperar a que haya redManual, con sleepSí, con After=network-online.target
Logs automáticos en el journalSolo el lanzamientoToda la salida del script
Evitar dos ejecuciones solapadasManualSí, de serie
Retraso aleatorio para no saturarNoSí, con RandomizedDelaySec
Un timer de systemd formado por dos archivos: copia.timer lanza copia.service, que ejecuta el script y escribe en el journal
Dos archivos: el timer decide cuándo y el servicio decide qué.

Un ejemplo mínimo. Primero el servicio, en /etc/systemd/system/copia.service:

[Unit]
Description=Copia diaria de datos

[Service]
Type=oneshot
User=pi
ExecStart=/home/pi/scripts/copia.sh

Después el timer, en /etc/systemd/system/copia.timer:

[Unit]
Description=Lanza la copia cada día a las 03:30

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true

[Install]
WantedBy=timers.target

Y se activa con:

sudo systemctl daemon-reload
sudo systemctl enable --now copia.timer
systemctl list-timers

La salida del script queda en journalctl -u copia.service, sin redirecciones. Cambia pi por tu usuario: desde Bullseye, Raspberry Pi OS ya no crea el usuario pi por defecto.

Errores habituales

  • El script funciona a mano pero no en cron. Casi siempre es el PATH o una ruta relativa. Usa rutas absolutas para todo.
  • El script no tiene permiso de ejecución. Dale permiso con chmod +x script.sh o llámalo con su intérprete (/bin/bash script.sh).
  • Falta la línea #! al principio del script. Sin ella, cron no sabe con qué intérprete ejecutarlo.
  • Usar % sin escapar en el comando: la línea se corta y falla.
  • Editar /etc/crontab sin poner el usuario. Ese archivo, a diferencia de crontab -e, lleva un sexto campo con el usuario antes del comando.
  • Hora equivocada. Si la zona horaria no es la tuya, las tareas se lanzan desfasadas. Ajústala en sudo raspi-config, en Localisation Options.
  • La tarea depende de la red al arrancar y falla de vez en cuando con @reboot. Pásala a systemd.

Relacionados

Preferencias de accesibilidad

Perfiles rápidos

Texto y lectura

Tamaño del texto
Por defecto
Altura de línea
Por defecto
Espaciado entre letras
Por defecto
Espaciado entre palabras
Por defecto

Color

Movimiento y orientación

Cursor