...making Linux just a little more fun!

Using Crontab

By Joey Prestia

Joey's Notes image

Crontab is a very useful command used to run unattended scheduled tasks, which can decrease administrative time. There are also two similar commands: anacron and at. Anacron is for scheduling commands that do not require the computer to be on at all times; Anacron uses day-, week-, and month-type intervals. The "at" command runs a task once, at a set time, and can also be very useful. But most commonly used is crontab, because it is more versatile, and can be customized to run at any time interval.

At our college, we have several servers running scripts which back up critical data during off peak hours. We have automated these procedures by using cron. For example, the backup script brings several services to a stop, performs an rsync of any changes from the hot server to a duplicate cold server, performs a standard tape archive backup, and finally brings the halted services back online. I sure am glad I don't have to be present at 1:00 AM, when this operation is performed! Thanks to cron, all I have to do is load and unload the backup devices and check my mail every morning to make sure all went well. I also have other programs that are run periodically - I would hate to have to remember to run these scripts every day.

In administering your system, you will also need to use cron quite a bit. This is done via the 'crontab' file, which lists the times and the scripts to be executed. The system also has a default crontab file, /etc/crontab, which runs certain scripts at set times: hourly, daily, weekly, and monthly. This file can be kind of cryptic-looking at first - so let's take the mystery out of it by breaking it down.

[root@localhost ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
[root@localhost ~]#

The first part simply sets a few variables:

SHELL
The first line specifies the shell to use for parsing the command line. "/bin/sh" is the default.
PATH
Because cron runs as subshell process, we need to either specify a path or use a PATH statement in crontab. The reason for this is that we are not logging into a console when we run these jobs - so neither .bashrc or .bash_profile have been sourced, and we have no environment variables to work with as we do when we login as a regular user or as root. It's also important to remember that trying to output data without a console is pointless - there's no screen to display it on! - so you need to make sure that any output that you want to save is logged somewhere.
MAILTO
On the next line, we have a "MAILTO=" command sending the results of these cron jobs to the root user. If MAILTO is defined but empty, mail from 'cron' will simply be discarded; if it's not set, then it will be sent to the owner of the crontab. I will show a sample of this additional output, later.
HOME
The next line sets the home directory used by cron. If unspecified, it will default to the entry in the owner's /etc/passwd file.
# run-parts
This line is actually just a comment specifying the section, although "run-parts" is a command that will run all the scripts or programs in the directory that is specified. There is even a man page for run-parts.

The time field seems to be the part that everyone has problems with - unless you're familiar with it, it can seem pretty cryptic. The rest is very straightforward. The user column specifies the 'run-as' user, and the "run-parts" command runs the scripts in the specified directory. Note that the directories are named by the interval at which they're run; you could just place your scripts in the directory you wanted, and they would be run at the times that are already set in the time section. This is not a good idea, though, because you can forget they're in there. It's by far better to edit your crontab file and create your own cron job, because it's easier to get a listing of your cron jobs this way and fine-tune them through via the crontab command. Keep in mind that this is the system crontab file (it runs the system maintenance scripts and programs), so a user's crontab will look a little different - in fact, the structure will be different - so don't try to replicate this.

#		Time	      User      Command       Path

01   *   *   *   *    root      run-parts     /etc/cron.hourly
02   4   *   *   *    root      run-parts     /etc/cron.daily
22   4   *   *   0    root      run-parts     /etc/cron.weekly
42   4   1   *   *    root      run-parts     /etc/cron.monthly

The Basics

There are two files that specify which users can and cannot use crontab: /etc/cron.allow and /etc/cron.deny. Usually, only cron.deny exists, and it really couldn't be much simpler: If cron.deny is present, and the user's username is in it (one user per line), then he or she is denied use of the crontab command. If cron.allow is present, then only users listed (one per line) in this file are allowed crontab use.

In the crontab file, there are six fields for each entry, each field separated by spaces or tabs.

          Minute - 0-59.
          Hour - 0-23 24-hour format.
          Day - 1-31 Day of the month.
          Month - 1-12 Month of the year.
          Weekday - 0-6 Day of the week. 0 refers to Sunday.

In the file, this would look as follows (the comments aren't necessary, but they can be very convenient as a reminder):

# min(0-59)    hours(0-23)   day(1-31)   month(1-12)    dow(0-6)   command
   34               2           *            *             *       sh /root/backup.sh

This example runs, at 2:34 AM every day of the month, every month of the year, every day of the week, the backup script called in the last column by "sh /root/backup.sh".

[ This, of course, requires the script to be written in strict 'sh' syntax - e.g., any "Bash-isms" would cause errors. As is the usual case with shell scripts, using a shebang which specifies the desired shell, making the script executable, and running it simply by specifying the name offers more precise control over the execution environment. -- Ben ]

A star in any position means 'every interval'; that is, a star in the 'minutes' slot would mean "execute this every minute".

Try It

Let's set up a cron task, just to see how easy it really is to do. The command we run is crontab -e, which will bring up a vi editor session [1] in which we set up our cron task. Also, you can space the numbers as far apart as you want, but I would recommend getting in the habit of using just one single space because you may need the extra space for the absolute path to whatever command you're running.

[root@localhost ~]# crontab -e

Now enter the following line:

* * * * * /usr/bin/wall "Hello From Crontab"

When you save it, you should see the following output:

crontab: installing new crontab
[root@localhost ~]#

In a few moments, you will see a message:

Broadcast message from root (Thu Apr  3 14:52:01 2008):

Hello From Crontab

This message will continue every minute, because we put stars in every time field; if we do not remove this crontab after we're satisfied, we will be greeted every minute for the rest of our lives. This is also a good demonstration of what crontab can do if you make a mistake! We will need to execute "crontab -r" to remove the entry.

[root@localhost ~]# crontab -r

Now, say at a certain time in the future you need to start the Apache 'httpd' Web server. We could use a cron job to do this. First, we'll check to see that httpd is not running. Then, we'll do a "date" command to get the current time, so we can set the service to run in the future.

[root@localhost ~]# service httpd status
httpd is stopped
[root@localhost ~]# 
[root@localhost ~]# date
Thu Apr  3 15:45:32 MST 2008
[root@localhost ~]#

We can now easily figure out what 10 minutes from now will be, execute crontab -e in the editor, and write a simple crontab file, remembering the format.

# min(0-59)    hours(0-23)   day(1-31)   month(1-12)    dow(0-6)   command

   55	          15           *            *		*  	/sbin/service httpd start

For now, just use stars for the day, month, and day of week, and only one space between elements; some distros complain if you have more spaces. So, enter something like this:

55 15 * * * /sbin/service httpd start
[root@localhost ~]# crontab -e 
crontab: Installing new crontab

If you made any mistakes, 'crontab' will tell you about it right as you close the editor. Assuming that everything was right, though, we will have the Apache Web server running less than ten minutes from now. You can use "crontab -l" to list your jobs at any time, to see what is in your crontab and when these jobs are set to run:

[root@localhost ~]# crontab -l 
55 15 * * * /sbin/service httpd start

Yours should look similar. What this means, though, is that 'httpd' is still set to run every single day at the specified time. Again, we'll remove it by executing "crontab -r" to delete all the entries in the file.

[root@localhost ~]# crontab -r

The combinations seem endless. There are also additional variations for specifying time: "20-27" specifies a range; "3,4,7,8" mean just those intervals for that selection; and */5 would be every 5th interval. Another feature of cron is that, upon completion of a job, it will mail the command output to the user who set up the cron job unless that feature is disabled.

Some more samples

This crontab entry would run the command every 15 and 30 minutes after every hour, during the month of May:

15,30 * *  5 * /usr/bin/command

To run a backup script on just Sundays, Mondays, and Tuesdays at 2:12 AM, the entry would be:

12 2 * * 0-2 sh /root/backup.sh

To run a script at 12 minutes after every 3rd hour of every day, the entry would look like this:

12 */3 * * * sh /root/script.sh

To get cron to write the output of the commands to a log, you can append something like this to the command entry:

12 */3 * * * sh /root/script.sh >> /root/script.log 2>&1

To have cron suppress the e-mail:

12 */3 * * * sh /root/script.sh > /dev/null 2>&1

This is a sample of cron output that would end up in the mail

From root@localhost.localdomain  Thu Apr  3 12:08:01 2008
Date: Thu, 3 Apr 2008 12:08:01 -0700
From: root@localhost.localdomain (Cron Daemon)
To: root@localhost.localdomain
Subject: Cron <root@localhost> sh /root/s.sh
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>

test

Some tips for using cron:

Commands:

crontab -e - Edits the current crontab, or creates a new one.
crontab -l - Lists the contents of the crontab file.
crontab -r - Removes the crontab file.
crontab -u - Edits user's crontab.


[1] Rick Moen comments: Strictly speaking, on most systems, "crontab -e" will invoke whatever is defined by the VISUAL or EDITOR environment variables.

Talkback: Discuss this article with The Answer Gang


[BIO]

Joey was born in Phoenix and started programming at the age fourteen on a Timex Sinclair 1000. He was driven by hopes he might be able to do something with this early model computer. He soon became proficient in the BASIC and Assembly programming languages. Joey became a programmer in 1990 and added COBOL, Fortran, and Pascal to his repertoire of programming languages. Since then has become obsessed with just about every aspect of computer science. He became enlightened and discovered RedHat Linux in 2002 when someone gave him RedHat version six. This started off a new passion centered around Linux. Currently Joey is completing his degree in Linux Networking and working on campus for the college's RedHat Academy in Arizona. He is also on the staff of the Linux Gazette as the Mirror Coordinator.


Copyright © 2008, Joey Prestia. Released under the Open Publication License unless otherwise noted in the body of the article. Linux Gazette is not produced, sponsored, or endorsed by its prior host, SSC, Inc.

Published in Issue 151 of Linux Gazette, June 2008

Tux