Penguin

Introduction

Scheduling under Linux is provided by the cron(8) daemon. It reads a file called a crontab(5), but you don't necessarily need to edit any cron table directly.

Running commands at standard intervals

On most systems, the easiest thing you can do if you simply want your command to be run once an hour, or once a day, or once a week, etc, is to put a script in the corresponding one of the /etc/cron.{hourly,daily,weekly,monthly} etc directories. This is a simple Shell script, not a crontab(5) file. On most systems, all the “daily” scripts will be run sometime in the wee hours, such as 4am.

Something to note is that this is usually done by a script called run-parts which has strange restrictions on what it considers a valid filename. The Linux Standard Base seems to be to blame for this: LSB: Cron jobs. DebianLinux' version of run-parts is even worse, defaulting to their legacy scheme which only allows [A-Za-z0-9_-] chars! This means it will silently ignore any scripts that contain a dot in the name, which is a horrible bug.

Running commands at custom times/intervals

If you need to run commands at custom times or intervals, you need to know the crontab(5) line format described in the ManPage. Read that now, if you don't know about it yet.

The main, system wide crontab(5) is /etc/crontab, but on most LinuxDistributions, there is a /etc/cron.d directory where you should put single line crontab files, eg:

# /etc/cron.d/exim: crontab fragment for exim
# Run queue every 15 minutes
08,23,38,53 * * * *     mail   if [ -x /usr/sbin/exim -a -f /etc/exim/exim.conf ]; then /usr/sbin/exim -q ; fi

This will be run every 15 minutes (8 past the hour, 23 past the hour etc) on every hour, every day, etc, as user mail. The initial fields are delimited by spaces, up to the the command (if [ ... ] ; then ... ; fi), which is taken as a whole to the end of the line. (The if bit is a sanity check to ensure a runnable Exim binary and an exim.conf file exist.)

Users can also have their own cron tables, with commands run under their respective UID. These should be manipulated using the crontab(1) command. crontab -e will launch your configured interactive TextEditor on your user crontab, which generally resides under /var/spool/cron.

Running commands at standard intervals, revisited, and more

With Vixie Cron (used in *BSD and some LinuxDistributions such as Debian and RedHat) you can use several special keywords instead of a time specification. This FreeBSD 4.1 manpage, where this feature first appears, lists the following keywords:

 string   meaning 
 @reboot   Run once, at startup. 
 @yearly   Run once a year, 0 0 1 1 *
 @annually   (sames as @yearly) 
 @monthly   Run once a month, 0 0 1 * *
 @weekly   Run once a week, 0 0 * * 0
 @daily   Run once a day, 0 0 * * *
 @midnight   (same as @daily) 
 @hourly   Run once an hour, 0 * * * *

@reboot is particularly interesting, as cron will run such a command at system startup. This allows regular users to start their own daemons such as fetchmail(1) at boot time.

Troubleshooting

Command isn't being run properly

  • cron uses a minimal PATH EnvironmentVariable. Explicitly set the PATH variable if you want anything not in /usr/bin and /bin (+ maybe /usr/local?)
  • You have a "%" symbol in your command, and cron treats this in a special fashion. From the crontab(5) ManPage:

The entire command portion of the line, up to a newline or % character, will be executed by /bin/sh or by the shell specified in the SHELL variable of the crontab file. Percent-signs (%) in the command, unless escaped with backslash (\), will be changed into newline characters, and all data after the first % will be sent to the command as standard input. There is no way to split a single command line onto multiple lines, ala the shell’s trailing "\".