Ejecutar programas por horario en Linux

Introducción
Muchos sistemas operativos Linux incluyen el servicio crontab, el cual es extremadamente útil para ejecutar programas ya sea en una fecha específica, o con alguna periocidad. La resolución máxima de crontab es de un minuto y la mínima es de una vez al año.

Para usar crontab se debe editar el archivo de configuración, para eso, es necesario escribir en la consola:
crontab -e
. Una vez escrito el comando, se debe escojer el editor de texto que se desea utilizar para editar el archivo de configuración. El archivo de configuración es pequeño y simple, por lo que se recomienda utilizar la opción nano. Deberías ver algo similar a esto:

archivo de configuración de crontab utilizando nano

En nano, para guardar y salir, debes apretar "ctrl+x", luego "y" y finalmente Enter.
La periocidad se define en crontab con el siguiente formato:
m h dom mon dow commando
Donde las variables son (de izquierda a derecha):
  • m: minuto. toma valores 0-59
  • h: hora. toma valores 0-23
  • dom: día del mes. toma valores 1-31.
  • mon: mes. toma valores 1-12 (o nombres)
  • dow: dia de la semana. toma valores 0-7 (0 y 7 es Domingo).
  • commando: el comando que deseas ejecutar en el horario establecido.
Por ejemplo, para correr un script de python llamado correr.py el jueves 30 de mayo a las 23:17 horas:
#todos los jueves 30 de mayo a las 23:17
17 23 30 5 4 /usr/bin/python /home/lab/correr.py
Notemos lo siguiente:
  • Es necesario utilizar rutas absolutas, incluso en el script correr.py.
  • El script va a correr todos los años que sea jueves el 30 de mayo (2019, 2024, 2030, etc)
Podemos hacer que el script corra todos los 30 de mayo a las 23:17, si hacemos:
#todos los 30 de mayo a las 23:17
17 23 30 5 1,2,3,4,5,6,7 /usr/bin/python /home/lab/correr.py
Podemos escribir un rango, del 1 al 7 haciendo:
#todos los 30 de mayo a las 23:17
17 23 30 5 1-7 /usr/bin/python /home/lab/correr.py
Podemos reemplazar "todos los valores", por un asterísco "*", por lo tanto, equivalentemente podemos escribir:
#todos los 30 de mayo a las 23:17
17 23 30 5 * /usr/bin/python /home/lab/correr.py
Podemos hacer que este código corra todos los 30 de mayo cada 15 minutos:
#todos los 30 de mayo cada 15 minutos
*/15 * 30 5 * /usr/bin/python /home/lab/correr.py
Podemos hacer que este código corra todos los 30 de mayo y 5 al 15 de mayo cada 15 minutos:
#todos los 30 de mayo y 5 al 15 de mayo cada 15 minutos
*/15 * 30,5-15 5 * /usr/bin/python /home/lab/correr.py
Podemos agregarle mucha más complejidad, por ejemplo:
#cada 15 minutos y en el minuto 10 de las horas 00 y 12, del 1 al 15 de mayo más los días pares, de los meses mayo a diciembre solo si es lunes, miercoles o jueves.
*/15,10 */12 1-15,*/2 5-12 1,3-4 /usr/bin/python /home/lab/correr.py
Típicamente no se hacen configuraciones tan complejas. Es muy común querer ejecutar un comando cada minuto:
#cada 1 minuto
* * * * * /usr/bin/python /home/lab/correr.py
O cada 10 minutos:
#cada 10 minutos
*/10 * * * * /usr/bin/python /home/lab/correr.py
Una vez al día a las 12:00:
#Una vez al día a las 12:00
0 12 * * * /usr/bin/python /home/lab/correr.py
Consideraciones importantes de crontab:
  • Es necesario utilizar rutas absolutas, incluso en el script correr.py.
  • cron requires that each entry in a crontab end in a newline character. Es decir, no olvidar dejar un espacio en blanco al final del crontab.
  • Puedes instalar un crontab como superuser haciendo sudo crontab -e
  • Asegurate que el comando corre si lo ejecutas desde la consola, en este ejemplo: /usr/bin/python /home/lab/correr.py. Debuggear en crontab es dificil.
  • A veces un código podría no correr igual cuando lo ejecutas desde la consola, esto podría deberse a que la variable $PATH, no está seteada correctamente en el crontab.
Para setear la variable $PATH en el crontab, hacer en una terminal:
echo $PATH
Luego copiar el string de la siguiente manera al comienzo del crontab (utiliza el string que te salió a ti):
export PATH=$PATH:/home/lab/bin:/home/lab/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin