0
from crontab import CronTab

tab = CronTab()
cmd1 = 'actual command'

cron_job = tab.new(cmd)
cron_job.minute.every(1)
cron_job.enable()
tab.write_to_user(user=True)

I have tried using minute.at(1) to run at the first minute, but I don't know whats the right way to run the command at a fixed time (6 am), just once.. I know "every" ends up repeating it, but I don't want that. The caveat is I need to use python-crontab.

adhawan
  • 13
  • 5

2 Answers2

2

The crontab syntax is: mm hh dd mt wd. So to set it to every morning at 6am it would be 00 06 * * * meaning 06:00 (24 hr time) of any day, month, weekday. If I'm referring to the documentation correctly, this should work:

from crontab import CronTab

tab = CronTab()
cmd1 = 'actual command'

cron_job = tab.new(cmd)
cron_job.setall('00 06 * * *')
cron_job.enable()
tab.write_to_user(user=True)
heinst
  • 7,458
  • 5
  • 34
  • 73
0

The linux cron command is designed especially for running a command periodically, while the at command is for running a job once, although it could be used to run a command repeatedly if that command resubmits itself. I do not know of a normal way to configure a cron entry to execute only once and cannot find any documentation about that being possible. It would be possible to remove the cron entry after it has run by executing 'crontab -e' to edit the crontab file and then deleting the entry for the job in the editor, or by overwriting everything in the crontab file with 'crontab < /dev/null' or by removing the crontab file entirely with 'crontab -r'.

Consideration of this leads me to invent the self-destructing cron job and it goes like this. Lets say you configure a cron job as yourself with user name 'adhawan. All that's needed to make the job self-destructing is to use the following as the last statement in the job's script:

crontab -r

This removes your crontab file and should work because your personal cron job runs as you. I tried it with the following job and it worked as expected - ran once and then removed itself!:

* * * * * echo hello > /var/tmp/cron1; crontab -r

As already mentioned, the Linux/Unix at utility provides a means to run something once at a scheduled time. The time is specified with something called a timespec (time specificiation). For example, to schedule a job to run only once at 6 am tomorrow, the following timespec could be used

6 am tomorrow

or to do it on September 18 at 6 AM the following could be used

6am Sep 18

or to also specify the year

6 am 9/18/2015

at's timespec grammar is very flexible. Using recent terminology it can be called DSL (domain specific language). It is implemented with YACC (yet another compiler compiler) and a reduced version of its grammar can be seen in its timespec file which is usually installed at /usr/share/doc/at*/timespec and online there is a copy of it at Abbreviated version of the yacc grammar used by at(1).

at can get the job to run from a file provided its executed with the -f option or from stdin. For example from a file named atjob:

at -f atjob 6 am Sep 18

or from stdin with redirection from a file:

at 6 am Sep 18 < atjob

or from stdin with a pipe:

cat atjob | at 6 am 9/18

Try using at from the command line first to schedule a command in the very near future, like now or in a minute, so you can see if it worked, and with a very simple command that produces something observable such as a new file. For example the first test job could be 'echo hello > /tmp/atfile01' and the first test at job could be submitted like this:

echo "echo hello > /tmp/atfile01" | at now

After running that, check to see if /tmp/atfile01 exists and if it does that proves the at system is operational.

Then try sheduling a job to run at 6am Sep 18 (or several days from now if today is Sep 18 or using your timespec) with

echo "echo hello > /tmp/atfile02" | at 6am Sep 18

If that didn't produce an error, then it worked, which can be confirmed by running atq and see if it lists a job scheduled for YYYY-09-18 06:00, where YYYYY is the current year or next year if this year's 9/18 has already passed.

Now you know how to write and run at jobs and it would be good to remove any test jobs from your at queue with atrm using atq to list the jobs including their ids and then executing atrm on the ids. For example, supposing the ids are 2, 10 and 17 the atrm command would be:

atrm 2 10 17

Now modify your working at command to suit your purpose and execute it from Python using subprocess, sh or envoy. Examples of using suprocess are at Calling an external command in Python.

For more information on at you can see its man page by running "man at" and an Ubuntu manpage for it is at.1posix.html.

Community
  • 1
  • 1
  • Thanks @Tris Nefzger. So python-crontab can not do it ... with something like: cron_job.hour.at(24) ? – adhawan Sep 17 '15 at 17:15
  • @adhawan: sure you could setup an at job with a cron job and you could remove a cron job with a cron job but in the end there is still a cron job waiting to do it again. However, I figured out a way to do what you want - the self-destructing cron job. It's explained in the second paragraph of my answer. –  Sep 18 '15 at 01:28