Wednesday, May 8, 2013

Unix: Timing your cron jobs

Most of my Unix admin cronies cut their teeth on tools like cron.
There is nearly nothing as fundamentally essential to administering Unix
systems are writing scripts and then setting them up to run without
intervention. Even so, cron has become more versatile over the decades
and there are a lot of nice "tricks" that you can use to tailor your
cron tasks to the work you need to do.
The traditional fields are fairly easy to remember -- as long as you
can keep in mind that the smallest time unit that you can address is
minutes and that the fields go from small units (minute) to large
(month) until you hit the day of week field. I still often tick off the
time fields on the fingers of my left hand. Let's see ...

____
.'` __/_______ minute after the hour (0-59)
---' -'` ______) hour of the day (0-23)
_______) day of the month (1-X where X depends on the month)
_______) month of the year (1-12)
-----..___________) day of the week (0-6)

And, of course, an * in any of these time fields to mean "any" of the legitimate values

As an example, this cron taks would run every 15 minutes after the hour:

15 * * * * /usr/local/runtask

Easy enough! But there are many options that make scheduling tasks to run very frequently or very infrequently even easier.
For one thing, you can tell cron to run a process multiple times an
hour, multiple times within a day, or even multiple times in a week by
selecting two values and separating them with a comma. The value 6,18
in the hour field, for example, might tell cron to run a task at 6 AM
and 6 PM:

0 6,18 * * * /usr/local/runtask

where this one would tell cron to run the process at 6:15 AM, 6:45 AM, 6:15 PM and 6:45 PM:

15,45 6,18 * * * /usr/local/runtask

You can also tell cron to run your tasks over a range of values -- such
as Monday through Friday (and not on the weekends) or from 8 AM to 6 PM
as shown here:

0 23 * * 1-5 /usr/local/weekdays
0 8-18 * * 1-5 /usr/local/workhours

And, while I've seen numerous instances of "0,15,30,45" used to run a
job every 15 minutes, the */15 specification does the same thing and is
neater and easier.
I was also quite surprised when I first noticed that the strings sun,
mon, tue, wed, thu, fri and sat also work for the day of the week
field. I've become so used to 0-6 that I sometimes refer to Saturdays
as "day 6" and confuse my friends.
Linux systems also provide some very useful shorthands for running
tasks at infrequent intervals. Instead of the five time fields shown
above, you can use any of these:
@yearly runs on January 1st at zero at 00:00 (equivalent to 0 0 1 1 *)
@monthly runs on the first of every month at 00:00 (equivalent to 0 0 1 * *)
@daily runs at the beginning of every day (equivalent to 0 0 * * *)
@hourly runs every hour (equivalent to 0 * * * *)
@reboot runs when the system boots
These top four options are very handy as long as you're happy to run your tasks at 00:00. Otherwise, you need to
set your time values using the typical five fields.
Cron allows you to run a task as frequently as once a minute and as
infrequently as once every 6-7 years (e.g., if you run a process at 6 AM
on the 13th of May only if it's a Friday).

* * * * * /usr/local/everyminute
10 10 13 5 5 /usr/local/almostnever

Anther useful thing to know in case you're new to cron is that, by
setting your EDITOR environment variable, you can tell crontab -- the
command you must use to edit or display your cron tasks -- which editor
you want to use to set up your cron tasks. This will normally default
to vi.