Saturday, July 6, 2013

Crontab (and running it on Mountain Lion)

crontab

crontab is a simple, useful *nix tool for scheduling tasks.

Perhaps you have a script that checks the contents of a directory (maybe to look for new or modified files and then do something with them).  Maybe you want this script to run every 30 minutes.  Or maybe you want it to run every 30 minutes, but only on Tuesdays and Thursdays when the date is even numbered.  Cron is perfect for this.


crontab syntax

Jobs are specified in the following format:

MIN HOUR DAY-of-MONTH MONTH DAY-of-WEEK <command you want to run>

All of these fields are two digits (except for DAY-of-WEEK, which is 0-6 i.e. Sun-Sat); single digits require a leading 0 (ex. 1AM = 01)

Time is on a 24 hr clock (ex. 1PM = 13)

You can also specify ranges, lists, etc.

Here are three examples:

situation: run a python script every ten minutes
job: 10 * * * * python /path/to/script.py

situation: run a python script at 6,8,10AM
job: 00 6,8,10 * * * python /path/to/script.py

situation: run a python script at Mon-Fri, every 10 min
job: */10 * * * 1-5 python /path/to/script.py

There are a few other things that can be used in lieu of "* * * * *":

@yearly (12AM Jan 1)
@monthly (12AM of first day of the month)
@weekly (12AM Sunday)
@daily (daily at 12AM)
@hourly (top of the hour)
@reboot (at startup)


scheduling jobs

create a new cron job with: 
crontab -e

Note: each job should be listed on its own line.

to see what jobs are scheduled:
crontab -l

to delete all scheduled jobs (be careful):
crontab -r


Getting it to work nicely on a Mac

So now you know how and why you might want to use crontab.  If you happen to be trying this on a mac, you might run into trouble when trying to schedule a task for the first time...

I could be wrong, but it seems to me like crontab used to be working without any problems when I was still using Snow Leopard.

The system doesn't want just anyone scheduling jobs.

One workaround...

sudo su -
crontab -u <yourusername> -e

That works, but it's a bit of a pain in the ass, right?  I'm the primary (effectively only) user on this machine, but I don't want to be forced to live in root land.


A better solution

After taking a look at the manual (man crontab), I found a better solution.

There are two files of interest, neither of which may currently exist on your system.

The files are:

/usr/lib/cron/cron.allow
/usr/lib/cron/cron.deny

If you follow the manual, you may discover that your username not being listed in "/usr/lib/cron/cron.deny" may not be enough to give you permission to schedule cron jobs.

Despite what the manual claims, you may need a "cron.allow" file.

Since I didn't have "cron.allow", I had to make the file...

sudo touch /usr/lib/cron/cron.allow

#instead of 'subl', use your editor of choice here
sudo subl /usr/lib/cron/cron.allow

You can probably combine those two steps into one.

Add your username(s) to this file.  Each username should be placed on its own line (check the manual if you run into problems).  

When you close the file, you may be prompted for a password.

Ok, now things should work properly.

add jobs with:
crontab -e

confirm your scheduled jobs with:
crontab -l


An example

I have trouble remembering a new weekly commitment. Feeling especially geeky, I decided to schedule a reminder via python and cron.

Here's a quick example script that is very bare bones:

#!usr/bin/python

import Tkinter, tkMessageBox

root = Tkinter.Tk()
root.withdraw()
#change the message to whatever you like
tkMessageBox.showinfo(title="Reminder",message="Your student/office hour in the lab starts at 11!")

This is a very simple example. If you're on a Mac, you could add these lines:

import os
os.system("say '01111011100001. Ooops. I forgot that you do not speak computer. Well, allow me to translate... Good Morning, you forgetful waste of carbon! Do not forget about your office hour.'")


Anyway, save that script (reminder.py) whereever you want.  I put it on the Desktop.

Next, fire up your cron scheduler with:
cron -e

add this line (or change it to your liking):
40 09 * 07-08 1 python ~/Desktop/reminder.py

save and exit.

Can you read cron schedules, yet?

"40 09 * 07-08 1" means run the script at 9:40AM every Monday during July and August


Conclusion

You don't need to be there to push that button.  Play around with scheduling tasks.  It can be very useful.

No comments:

Post a Comment