Programación de trabajos con python-crontab

Cron es una utilidad de software que nos permite programar tareas en sistemas tipo Unix. El nombre se deriva de la palabra griega Chronos, que significa ...

Qué es Crontab

Cron es una utilidad de software que nos permite programar tareas en sistemas tipo Unix. El nombre se deriva de la palabra griega "Chronos", que significa "tiempo".

Las tareas en cron se definen en un crontab, que es un archivo de texto que contiene los comandos a ejecutar. La sintaxis utilizada en un crontab se describe a continuación en este artículo.

Python nos presenta el módulo crontab para gestionar trabajos programados a través de Cron. Las funciones disponibles en él nos permiten acceder a Cron, crear trabajos, establecer restricciones, eliminar trabajos y más. En este artículo, mostraremos cómo usar estas operaciones desde dentro del código de Python.

Para el lector interesado, la página de ayuda oficial se puede encontrar en https://pypi.python.org/pypi/python-crontab.

Sintaxis crontab

Cron usa una sintaxis específica para definir los horarios. Consta de cinco campos, que están separados por espacios en blanco. Los campos son:

1
Minute Hour Day Month Day_of_the_Week

Los campos pueden tener los siguientes valores:

1
2
3
4
5
6
7
8
9
┌───────────── minute (0 - 59)
 ┌───────────── hour (0 - 23) 
  ┌───────────── day of month (1 - 31)
   ┌───────────── month (1 - 12)
    ┌───────────── day of week (0 - 6) (Sunday to Saturday;
                                           7 is also Sunday on some systems)
    
    
* * * * *  command to execute

[Fuente: Wikipedia. Cron. Disponible en https://en.wikipedia.org/wiki/Cron]{.small}

Cron también acepta caracteres especiales para que pueda crear horarios más complejos. Los caracteres especiales tienen los siguientes significados:

Carácter Significado


Coma Para separar varios valores Guión Para indicar un rango de valores Asterisco Para indicar todos los valores posibles Barra inclinada Para indicar CADA

Veamos algunos ejemplos:

  1. * * * * * significa: cada minuto de cada hora de cada día del mes de cada mes de cada día de la semana.
  2. 0 16 1,10,22 * * le dice a cron que ejecute una tarea a las 4 p. m. (que es la hora 16) los días 1, 10 y 22 de cada mes.

Instalación de Crontab {#instalación de crontab}

Crontab no está incluido en la instalación estándar de Python. Así, lo primero que tenemos que hacer es instalarlo.

Esto se hace con el comando pip. Lo único a considerar es que el nombre del módulo es 'python-crontab', y no solo 'crontab'. El siguiente comando instalará el paquete en nuestra máquina:

1
$ pip install python-crontab

Obtener acceso a Crontab

De acuerdo con la página de ayuda de crontab, hay cinco formas de incluir un trabajo en cron. De ellos, tres funcionan solo en Linux y dos también se pueden usar en Windows.

La primera forma de acceder a cron es usando el nombre de usuario. La sintaxis es la siguiente:

1
cron = CronTab(user='username')

Las otras dos formas de Linux son:

1
2
3
4
5
cron = CronTab()

# or

cron = CronTab(user=True)

Hay dos sintaxis más que también funcionarán en Windows.

En el primero, llamamos a una tarea definida en el archivo "filename.tab":

1
cron = CronTab(tabfile='filename.tab')

En el segundo, definimos la tarea según la sintaxis de cron:

1
cron = CronTab(tab="""* * * * * command""")

Creando un nuevo trabajo

Una vez que hayamos accedido a cron, podemos crear una nueva tarea usando el siguiente comando:

1
cron.new(command='my command')

Aquí, my command define la tarea que se ejecutará a través de la línea de comandos.

También podemos añadir un comentario a nuestra tarea. La sintaxis es la siguiente:

1
cron.new(command='my command', comment='my comment')

Veamos esto en un ejemplo:

1
2
3
4
5
6
7
from crontab import CronTab

cron = CronTab(user='username')
job = cron.new(command='python example1.py')
job.minute.every(1)

cron.write()

En el código anterior, primero accedimos a cron a través del nombre de usuario y luego creamos un trabajo que consiste en ejecutar un script de Python llamado ejemplo1.py. Además, hemos configurado la tarea para que se ejecute cada 1 minuto. La función write() agrega nuestro trabajo a cron.

El script ejemplo1.py es el siguiente:

1
2
3
from datetime import datetime
myFile = open('append.txt', 'a') 
myFile.write('\nAccessed on ' + str(datetime.now()))

Como podemos ver en el código anterior, el programa se abrirá y agregará la frase "Se accedió el" con la fecha y hora de acceso agregadas.

El resultado es el siguiente:

archivo append.txt{.img-responsive}

Figura 1

Como esperábamos, la Figura 1 muestra que el programa accedió al archivo. Continuará realizando la tarea asignada mientras el programa example1.py se ejecuta en cron.

Una vez que se accede a cron, podemos agregar más de un trabajo. Por ejemplo, la siguiente línea en el ejemplo anterior agregaría una segunda tarea para ser administrada por cron:

1
job2 = cron.new(command='python example2.py')

Una vez que se agrega una nueva tarea, podemos establecer restricciones para cada una de ellas.

Establecer restricciones

Una de las principales ventajas de usar el módulo crontab de Python es que podemos configurar restricciones de tiempo sin tener que usar la sintaxis de cron.

En el ejemplo anterior, ya hemos visto cómo configurar la ejecución del trabajo cada minuto. La sintaxis es la siguiente:

1
job.minute.every(minutes)

Del mismo modo podríamos configurar las horas:

1
job.hour.every(hours)

También podemos configurar la tarea para que se ejecute en determinados días de la semana. Por ejemplo:

1
job.dow.on('SUN')

El código anterior le indicará a cron que ejecute la tarea los domingos, y el código siguiente le indicará a cron que programe la tarea los domingos y viernes:

1
job.dow.on('SUN', 'FRI')

Del mismo modo, podemos decirle a cron que ejecute la tarea en meses específicos. Por ejemplo:

1
job.month.during('APR', 'NOV')

Esto le indicará a cron que ejecute el programa en los meses de abril y noviembre.

Una cosa importante a tener en cuenta es que cada vez que establecemos una restricción de tiempo, anulamos la anterior. Así, por ejemplo:

1
2
job.hour.every(5)
job.hour.every(7)

El código anterior configurará el horario final para que se ejecute cada siete horas, cancelando el horario anterior de cinco horas.

A menos que agreguemos un horario a uno anterior, como este:

1
2
job.hour.every(15)
job.hour.also.on(3)

Esto establecerá el horario como cada 15 horas, y a las 3 AM.

La condición 'every' puede ser un poco confusa a veces. Si escribimos job.hour.every(15), esto será equivalente a * */15 * * *. Como podemos ver, los minutos no han sido modificados.

Si queremos poner el campo de minutos a cero, podemos usar la siguiente sintaxis:

1
job.every(15).hours()

Esto establecerá la programación en 0 */4 * * *. Del mismo modo para los campos 'día del mes', 'mes' y 'día de la semana'.

Ejemplos:

  1. trabajo.cada(2).mes es equivalente a 0 0 0 */2 * y trabajo.mes.cada(2) es equivalente a * * * */2 *
  2. job.every(2).dows es equivalente a 0 0 * * */2 y job.dows.every(2) es equivalente a * * * * */2

Podemos ver las diferencias en el siguiente ejemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from crontab import CronTab

cron = CronTab(user='username')

job1 = cron.new(command='python example1.py')

job1.hour.every(2)

job2 = cron.new(command='python example1.py')
job2.every(2).hours()

for item in cron:
    print item

cron.write()

Después de ejecutar el programa, el resultado es el siguiente:

1
2
3
4
$ python cron2.py
* */2 * * * python /home/eca/cron/example1.py
0 */2 * * * python /home/eca/cron/example1.py
$

Figura 2

Como podemos ver en la Figura 2, el programa ha establecido los minutos de la segunda tarea en cero y ha definido los minutos de la primera tarea en su valor predeterminado.

Finalmente, podemos configurar la tarea para que se ejecute cada vez que iniciamos nuestra máquina. La sintaxis es la siguiente:

1
job.every_reboot()

Eliminación de restricciones

Podemos borrar todas las restricciones de tareas con el siguiente comando:

1
job.clear()

El siguiente código muestra cómo usar el comando anterior:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from crontab import CronTab

cron = CronTab(user='username')

job = cron.new(command='python example1.py', comment='comment')
job.minute.every(5)

for item in cron:
    print item

job.clear()

for item in cron:
    print item
cron.write()

Después de ejecutar el código obtenemos el siguiente resultado:

1
2
3
$ python cron3.py
*/5 * * * * python /home/eca/cron/example1.py # comment
* * * * * python /home/eca/cron/example1.py # comment

Figura 3

Como podemos ver en la Figura 3, el horario ha cambiado de cada 5 minutos a la configuración predeterminada.

Habilitar y deshabilitar un trabajo {#habilitar y deshabilitar un trabajo}

Una tarea se puede habilitar o deshabilitar usando los siguientes comandos:

Para habilitar un trabajo:

1
job.enable()

Para deshabilitar un trabajo:

1
job.enable(False)

Para verificar si una tarea está habilitada o deshabilitada, podemos usar el siguiente comando:

1
job.is_enabled()

El siguiente ejemplo muestra cómo habilitar y deshabilitar un trabajo creado previamente y verificar ambos estados:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from crontab import CronTab

cron = CronTab(user='username')

job = cron.new(command='python example1.py', comment='comment')
job.minute.every(1)

cron.write()

print job.enable()
print job.enable(False)

El resultado es el siguiente:

1
2
3
$ python cron4.py
True
False

Figura 4

Comprobación de la validez

Podemos comprobar fácilmente si una tarea es válida o no con el siguiente comando:

1
job.is_valid()

El siguiente ejemplo muestra cómo usar este comando:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from crontab import CronTab

cron = CronTab(user='username')

job = cron.new(command='python example1.py', comment='comment')
job.minute.every(1)

cron.write()

print job.is_valid()

Después de ejecutar el programa anterior, obtenemos la validación, como se ve en la siguiente figura:

1
2
$ python cron5.py
True

Figura 5

Listado de todos los trabajos cron

Todos los trabajos cron, incluidos los trabajos deshabilitados, se pueden enumerar con el siguiente código:

1
2
for job in cron:
    print job

Agregar esas líneas de código a nuestro primer ejemplo mostrará nuestra tarea al imprimir en la pantalla lo siguiente:

1
2
$ python cron6.py
* * * * * python /home/eca/cron/example1.py

Figura 6

Encontrar un trabajo

El módulo crontab de Python también nos permite buscar tareas en base a un criterio de selección, que puede estar basado en un comando, un comentario o un horario programado. Las sintaxis son diferentes para cada caso.

Encuentra según el comando:

1
cron.find_command("command name")

Aquí 'nombre de comando' puede ser una subcoincidencia o una expresión regular.

Encuentra según el comentario:

1
cron.find_comment("comment")

Encuentra según el tiempo:

1
cron.find_time(time schedule)

El siguiente ejemplo muestra cómo encontrar una tarea previamente definida, de acuerdo con los tres criterios mencionados anteriormente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from crontab import CronTab

cron = CronTab(user='username')

job = cron.new(command='python example1.py', comment='comment')
job.minute.every(1)

cron.write()

iter1 = cron.find_command('exam')
iter2 = cron.find_comment('comment')
iter3 = cron.find_time("*/1 * * * *")

for item1 in iter1:
    print item1

for item2 in iter2:
    print item2

for item3 in iter3:
    print item3

El resultado es la lista del mismo trabajo tres veces:

1
2
3
4
$ python cron7.py
* * * * * python /home/eca/cron/example1.py # comment
* * * * * python /home/eca/cron/example1.py # comment
* * * * * python /home/eca/cron/example1.py # comment

Figura 7

Como puede ver, encuentra correctamente el comando cron cada vez.

Eliminación de trabajos

Cada trabajo se puede eliminar por separado. La sintaxis es la siguiente:

1
cron.remove(job)

El siguiente código muestra cómo eliminar una tarea que se creó previamente. El programa primero crea la tarea. Luego, enumera todas las tareas, mostrando la que se acaba de crear. Después de esto, elimina la tarea y muestra la lista vacía resultante.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from crontab import CronTab

cron = CronTab(user='username')

job = cron.new(command='python example1.py')
job.minute.every(1)

cron.write()
print "Job created"

# list all cron jobs (including disabled ones)
for job in cron:
    print job

cron.remove(job)
print "Job removed"

# list all cron jobs (including disabled ones)
for job in cron:
    print job

El resultado es el siguiente:

1
2
3
4
$ python cron8.py
Job created
* * * * * python /home/eca/cron/example1.py
Job removed

Figura 8

Los trabajos también se pueden eliminar en función de una condición. Por ejemplo:

1
cron.remove_all(comment='my comment')

Esto eliminará todos los trabajos donde comment='my comment'.

Borrando todos los trabajos

Todos los trabajos cron se pueden eliminar a la vez usando el siguiente comando:

1
cron.remove_all()

El siguiente ejemplo eliminará todos los trabajos cron y mostrará una lista vacía.

1
2
3
4
5
6
7
8
from crontab import CronTab

cron = CronTab(user='username')
cron.remove_all()

# list all cron jobs (including disabled ones)
for job in cron:
    print job

Variables ambientales {#variables ambientales}

También podemos definir variables ambientales específicas de nuestra tarea programada y mostrarlas en pantalla. Las variables se guardan en un diccionario. La sintaxis para definir una nueva variable ambiental es la siguiente:

1
job.env['VARIABLE_NAME'] = 'Value'

Si queremos obtener los valores de todas las variables ambientales, podemos usar la siguiente sintaxis:

1
job.env

El siguiente ejemplo define dos nuevas variables ambientales para la tarea 'usuario' y muestra su valor en la pantalla. El código es el siguiente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from crontab import CronTab

cron = CronTab(user='username')

job = cron.new(command='python example1.py')
job.minute.every(1)
job.env['MY_ENV1'] = 'A'
job.env['MY_ENV2'] = 'B'

cron.write()

print job.env

Después de ejecutar el programa anterior, obtenemos el siguiente resultado:

1
2
3
$ python cron9.py
MY_ENV1=A
MY_ENV2=B

Figura 9

Además, las variables de entorno a nivel de Cron se almacenan en 'cron.env'.

Finalizando

El módulo de Python crontab nos brinda una herramienta útil para administrar mediante programación nuestra aplicación cron, que está disponible para sistemas similares a Unix. Al usarlo, en lugar de tener que depender de la creación de crontabs, podemos usar el código de Python para administrar tareas frecuentes.

El módulo es bastante completo. Aunque ha habido algunas críticas sobre su comportamiento, contiene funciones para conectarse a cron, crear tareas programadas y administrarlas. Como se muestra en los ejemplos anteriores, su uso es bastante directo. Así, proporciona una herramienta que permite realizar scripts complejos con la principal característica de Python: la sencillez.

Licensed under CC BY-NC-SA 4.0