Disclaimer don't get the wrong idea about what you've found here

What appears below are my personal notes I wish were part of my long-term memory but don't always seem to fit. I strive for accuracy and clarity and appreciate feedback. If applying any of this information anywhere, confirm for youself the correctness of your work as what you see below might very well be, albeit unintentionally, incorrect or misleading. These notes are here as an easy reference for myself.

Information worthy of a more formal presentation will appear elsewhere than this "Scratch" area. - ksb


KSB's cron notes

I'm not sure I have ever written, even the simplest crontab entry, which worked as desired the first time. Herein are some hard-won lessons on how to write crontab entries.

Table of Contents References

The Basics

  1. The man page you most likely want is (in the "File Formats and Conventions" section):
    man 5 crontab
  2. Each cron tab entry consists of 6 fields in order:
    min hour day-of-month month day-of-week command
    0 3 * * * $HOME/bin/nightlies
    This, for example, will run the nightlies script at 3am each morning.

  3. You can define environment vars in the crontab file, including the special MAILTO var which identifies where output is sent.
    min hour day-of-month month day-of-week command
    MAILTO=me@example.com
    PATH=/usr/local/bin:/usr/bin:/bin
    0 3 * * * $HOME/bin/nightlies
  4. It always takes me several tries to get a crontab right. So I start with an entry which runs every other minute or so, editing and observing the result, via email or whatever, editing the crontab file again and again until I'm happy with it. For example:
    # min hour day-of-month month day-of-week command
    MAILTO=me@example.com
    */2 * * * * env | egrep ^PATH > $HOME/cron.out 2>&1
    This should print the contents of the $PATH env var used by cron to a file under your home dir and shows how to specify an every-other-minute cron job).

  5. Despite that I'm not doing it here, most non-trivial cron jobs are probably best moved into a script which doesn't generate any output at all, reporting it's output via whatever means you need (email, whatever). This has the advantage that they can be tested outside of cron and moved into a version control system, etc.

Gotchas

  1. crontab syntax is not sh syntax.

    For example, changing the above example to:

    # min hour day-of-month month day-of-week command
    MAILTO=me@example.com
    PATH=$PATH:$HOME/bin
    */2 * * * * env | egrep ^PATH > $HOME/cron.out 2>&1
    You might think would add ~/bin to your $PATH. Nope, you loose. In fact it effectively unsets the $PATH used so that now the env and egrep executables can't be found and nothing gets written to ~/cron.out. And you get an email like the following:
    env: not found
    egrep: not found

    What happens is the $PATH is not expanded into the value of the PATH env var. That newly added line will set your PATH to the literal (and meaningless) value '$PATH:$HOME/bin' not expanding the $HOME var either. Try this, instead:

    # min hour day-of-month month day-of-week command
    MAILTO=me@example.com
    */2 * * * * PATH=$PATH:$HOME/bin env | egrep ^PATH > $HOME/cron.out 2>&1

    A somewhat helpful trick is to try running your cron command directly via the shell, which gets you a bit closer to the way it will be run by cron:

    /bin/sh -c "PATH=$PATH:$HOME/bin env | egrep ^PATH > $HOME/cron.out 2>&1"
    This isn't fool-proof but if it doesn't work this way, it certainly won't work via cron.

  2. Don't use MAILTO alone unless you can receive mail at that account.

    Most machines these days do not accept mail, for lots of good reasons. So if for some reason someone, or something generates a reply to that email, it would be nice to have that go someplace that won't bounce or clog up a mailq somewhere.

    By default cron will set the From: field to be user@host, to change this you'll need to basically mail the results of your job manually, setting whatever mail headers you want. Here's a couple of ways to set the From: field of the emails you send.

    Using sendmail:

    # min hour day-of-month month day-of-week command
    MAILTO=me@example.com
    0 1 * * * (printf "From: Nightly work <me@example.com>\nTo: nightly-work-list@example.com\nSubject: Nighly work\n\n" && $HOME/bin/nightlies) 2>&1 | /usr/sbin/sendmail nightly-work-list@example.com

    Using mail:

    # min hour day-of-month month day-of-week command
    MAILTO=me@example.com
    0 1 * * * $HOME/bin/nightlies 2>&1 | /usr/bin/mail -a "From: Nightly work <me@example.com>" -s "Nightly work" nightly-work-list@example.com

    These both allow has the nice side-effect of being able to set the subject of the email to something better than the ugly default cron uses.

    Yes, you will do best to include both the To: header and the destination for sendmail, since some mail list will complain about "implicit sender".

    Also, if you're going to this much work, you might as well move the job into it's own script.

  3. Beware the '%' char.

    The '%' char in crontab files has a special meaning. Read the man page if you really want to know but this clobbered me when using the date command with a format string in it. You need to quote the % char in the normal way to avoid that special meaning:

    # min hour day-of-month month day-of-week command
    MAILTO=me@example.com
    0 1 * * * cvs -Q -d /path/to/cvs/repo up -D `date +\%Y-\%m-\%d` /path/to/cvs/workspace


Keith S. Beattie is responsible for this document, located at http://dst.lbl.gov/~ksb/Scratch/cron.html, which is subject to LBNL's Privacy & Security Notice, Copyright Status and Disclaimers.

Last Modified: Monday, 25-Feb-2013 16:57:57 PST