Obligatory XKCD… (Though I’m not sure Randall has a completely accurate understanding of the MAILTO variable which according to my reading of man cron is for addresses and not mail box directories. I could be the wrong one, but no thanks to the man page. This might be a difference of old school Vixie cron and newer cronie. See below.)

Vixie vs. Cronie

In the ancient times, a clever guy named Paul Vixie created cron and it was called cron. And that was fine. But then a lot happened and Paul had better things to do with his time (apparently) than mess about with cron. So some different people reimplemented it. Tons of them really, but the one that seems to be emerging as the best one to use for practical purpose is Cronie. Switching to this seems to cure the Gentoo braindead problem of new vixie-cron crontab edits not taking effect without a complete process restart. I think I’m one of the last people to actually use ancient sys-process/vixie-cron because I have been using it since ancient times and I didn’t know that it had been cast into the obscurity void.

Basic Usage

Cron uses a "crontab" which is a list of rules for what should happen when. To simply see what is in your crontab in a read-only non-destructive way use the crontab command with -l for list.

crontab -l

To edit these rules use this command which will properly lock the file and invoke your editor.

crontab -e

If the wrong editor opens the crontab you can fix that with something like this.

sudo apt-get install vim
sudo apt-get purge nano
echo 'export EDITOR=/usr/bin/vim' >> .bashrc
sudo update-alternatives --config editor

Here is a prototypical crontab.

My Sample Cron
MAILTO=xed@example.xed.ch
SHELL=/bin/bash

# Here is a sample cron tab that explains what goes where.
# Basically, don't put a * in the first two fields unless you
# want a LOT of action.
#
# minute
#  |   hour(0-23)
#  |    |   day of month(1-31)
#  |    |    |   month of year(1-12 or jan, Feb, mAR, etc)
#  |    |    |    |   day of week(0-6 (0=Sun), or mon, tUE, Wed, etc.)
#  |    |    |    |    |    COMMANDS
#  0    2    *    *    0,4   /sbin/something "Runs Sunday and Thursday at 2am"

# */2 means activate when TIME_UNIT MOD 2 == 0

# Normal style of entries.
30 * * * * /home/xed/somegood_hourly_script >/dev/null 2>&1
55 8 * * * /home/xed/somegood_daily_script

# Anniversary reminder example.
0 0 15 4 * echo "File your taxes yet?"

# Example alarm. Play a noise on weekdays at 1430 and 1442.
30,42 14 * * 1,2,4,5   /usr/bin/play -q /home/xed/collection/sounds/cattle.wav

# Check if drive is full. If not, ignore. If it is, send email. At 03h22 Sundays.
22 3 * * 0    df | grep "100. /"

Difficult Things To Specifiy

Every Fortnight

First you can test to make sure your system can use this technique.

* * * * * expr `date +\%M` \% 2 >>/dev/null || date >> ~/testdir/2weekcronttest

This produces something like:

Tue Sep 25 12:40:01 PDT 2012
Tue Sep 25 12:42:01 PDT 2012
Tue Sep 25 12:44:01 PDT 2012
Tue Sep 25 12:46:01 PDT 2012

If you want odd numbered minutes or weeks or whatever, use something like this:

* * * * * expr \( `date +\%M` + 1 \) \% 2 >>/dev/null || date >> ~/testdir/2weekcronttest

This isn’t too exciting since you can get every other minute by doing a */2 in the minute field. But it quickly proves the idea which will also work on weeks where the normal syntax breaks down.

If the test works out, then you can see that replacing the %M with %W will give you a cron job that runs on every even (or odd) week of the year. If the test doesn’t work, see the section on percents below.

Here’s a cron rule that runs biweekly (fortnightly):

0 11 * * thu expr `date +\%W` \% 2 >>/dev/null || /usr/local/bin/indexthedb

Mailing

First note the "MAILTO=" line which will take all standard output of the commands run by cron and send them to that specified email address.

Mail is generally a separate problem from cron and to make sure automatic notifications work, make sure that manual mail sending is good to go.

cal 2000 | mail -a "From: raven back-upper <logging@xed.com" \
                -s "subject goes here" logging@xed.com

Make sure you have mailx and ssmtp installed (Gentoo anyway) and look at /etc/ssmtp/ssmtp.conf.

If this works as planned then you can specify some mailing jobs in cron. That would look something like:

0 0 * * 0 echo "Weekly Backup Reminder" | /usr/bin/mail \
          -a "From: $(hostname) <logging@xed.ch>" \
          -s "Cron testing from sad" logging@xed.ch

You can try \ but I just put them here for illustration. Normally I’d just have all this on one line to be safe.

Caveats

Percent

In crontabs, "%" delimits the command’s standard input (the first percent) or signifies a new line within that input. The only use I can imagine for this is mailing things.

55 * * * * mail -a "From: Crontest <crontest@xed.ch>" \
                   -s "A Test Of Cron" \
                   xed@blackswan%This is a test.%This should be line 2 of the message.

This is helpful when you want cron to just send you reminder notes. I find, however, that pipes work just fine making this percent functionality more of a nuisance than anything.

It is theoretically possible to escape this behavior with a backslash like \% but I’ve had trouble getting that to work sometimes.

Another way to get a real "%" without including it on the command line is to use $'\x25' which is a bit complex but mostly works without messing up other things. This is a Bash substitution and it’s important to note that the vixie-cron daemon sets the SHELL value to /bin/sh by default. But you can add a line with SHELL=/bin/bash so that this kind of fancier substitution does work. Of course this may mess up other things.

Here’s a diagnostic sequence designed to regularly capture working conditions every 15 minutes in order to troubleshoot random failures. (Heat related? Memory? What kind of jobs were being run?)

2,17,32,47 * * * * SL=/local/xed/sensorlog ;\
                   date '+========== \%Y\%m\%d-\%H\%M' >>$SL;\
                   sensors >>$SL ; freeh -h >>$SL ;\
                   top -bn1 | head -n20 >>$SL

I conclusively had this work in cronie on CentOS 7.

Definitely test your entry before relying on it if it includes "%".

Gentoo

For some reason, changes made on some Gentoo systems with crontab -e are not taking effect. The vixie-cron daemon must be restarted:

$ sudo /etc/init.d/vixie-cron restart

I don’t know why that is but it’s wise to check to make sure that cron does what you think it’s supposed to be doing.

See my aforementioned remarks about Cronie as perhaps a better choice.

at

at is the lesser known little brother of cron. The at command is similar to cron in that it schedules jobs to be run at a later time, but at specifies a single fixed future point in time for the job to run as opposed to periodically.

at

  • …has a daemon process (atd) similar to crond to manage jobs.

  • …is for jobs set to run at specific times, not periodically (like cron).

  • …can also schedule jobs for when the cpu is unloaded.

  • …can email you when the job is complete.

  • …preserves environment it was run from (cron does not).

at Examples

Here are some simple examples. This is a very normal kind or thing:

echo '/home/xed/mknewyearbackups.sh 2014' | at midnight January 1 2014

I’m actually not sure if midnight is after the day specified or before. Need to check that.

Here is a good way to get rid of temp files:

$ echo "rm /tmp/mytempfile" | at now + 10 minutes

at Management

  • batch is an alias of at which runs jobs when the CPU load is low.

  • atq lists pending at jobs .

  • atrm removes pending at jobs .

  • See man at for all the details.

  • Also this web page is useful (it can be hard to search for good info on at).

at can use /etc/at.allow and /etc/at.deny. It may be smart to make these as symlinks to /etc/cron.allow and /etc/cron.deny if they exist.