Using cron to automate maintenance
The cron subsystem schedules tasks to run any hour of the day or night, making regular upkeep a breeze
Before you start
Learn what to expect from this tutorial and how to get the most out of it.
About this tutorial
This tutorial explains how to configure and maintain
the job scheduler found on almost all UNIX® machines. Additionally, this
lesson demonstrates just some of the many applications of
Learn how to create, schedule, and manage
and how to define timetables to control job frequency, from once per minute to
once per year. Additionally, learn how to limit access to
to prevent abuse and how to use other utilities in tandem with
to automate common maintenance tasks.
This tutorial is written for users and systems administrators of UNIX (and UNIX-like) systems. To follow this tutorial, you should have a general familiarity with a command-line shell and shell scripting. Some experience installing and configuring software on UNIX is also helpful.
To run the examples in this tutorial, you need a UNIX computer. If you want to
cron jobs, you also need root
access. The examples shown in this tutorial are based on Vixie
cron, which is used widely on modern UNIX systems,
running on Ubuntu Desktop Linux® version 8.04.1. Other versions of
cron are similar to Vixie; check the documentation
for your UNIX system for specifics.
Unlike you and me, a computer works tirelessly, applying the same vigor to every task great and small. Moreover, a computer gladly works 24 hours per day, seven days per week, including snow days and federal holidays.
The cron daemon
To leverage round-the-clock computing, though, tasks must run at all hours of
the day. You could punctuate your sleep with waking interludes to log in and
run this command or that on dozens of machines, or you can enjoy your 40
winks and turn the work over to the ubiquitous
a daemon (or perennial process) for executing commands on a schedule.
From very often to every so often,
minds the clock and runs jobs day or night.
Need to monitor an FTP drop-box for incoming data? Use
to run a shell script every few minutes. Need to delete scratch files that
accumulate during the day? Slate garbage collection for the middle of the
night. Want to rotate your log files on a regular basis? Set a weekly agenda.
Here, you learn how to configure and maintain
discover its many applications. Specifically, this tutorial looks at Vixie
cron, named after its author, Paul Vixie. Vixie
cron is found in FreeBSD, Apple Mac OS X, most
flavors of Linux, and other UNIX systems. To determine whether your system
man crontab, and look for the attribution for
Paul Vixie at the bottom.
To follow along with this article and to use
should be familiar with at least one text editor, such as vi or Emacs, and have
some experience with the UNIX command line, shell scripts, and shell
environment variables. Further, if you want to alter the system-wide
configuration files, you must have root, or superuser, access.
cron daemon is a small subsystem of utilities and
configuration files, and a flavor of
cron can be
found on nearly every UNIX-like system.
components include the daemon itself; a collection of system-wide configuration
files; a set of per-user configuration files; a utility to add, alter, and remove user
configuration files; and a simple access control facility. In general, a
cron configuration file or list of
jobs is called a crontab, short for
- The daemon,
cron, runs continuously, checking its configuration files for changes once per minute.
Cronreads the system-wide and per-user crontabs (described in the next two bullets, respectively), updates its schedule of events accordingly, and executes all commands scheduled to run in the current minute. The daemon also captures the output of each job, if any, and e-mails the result to the job's owner.
- System-related jobs can be defined in three places: in /etc/crontab,
in any file in /etc/cron.d, and in the special directories /etc/cron.hourly,
/etc/cron.daily, /etc/cron.weekly, and /etc/cron.monthly:
- The primary system crontab is /etc/crontab. The file has its own unique syntax (described in the next section), and each job defined in it runs according to its own timetable (such as twice an hour or every other day) and as a specific, named user. Use /etc/crontab to schedule miscellaneous administration and maintenance tasks.
- You can also maintain a suite of crontabs in the directory /etc/cron.d. Create a crontab to logically group commands that pertain to a specific subsystem. For example, the package for the PHP version 5 programming language installs a crontab named php5 in /etc/cron.d to periodically purge unused sessions. Files in /etc/cron.d have the same syntax as /etc/crontab, and each job runs per its unique timetable and as a particular user.
- As an alternative, you can simply drop a shell script into one of /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, or /etc/cron.monthly to run the script once per hour, once per day, once per week, or once per month, respectively. Scripts placed here run as the superuser.
- The collection of per-user crontabs is commonly found in /var/spool/cron/crontabs.
(Peruse the documentation for your UNIX system for the exact location.
Some systems keep user crontabs in /usr/lib.) However, you cannot directly
edit files in that directory. Instead, you create a crontab and submit the file
with the utility
crontab. Managing your personal
crontabis covered momentarily.
- Finally, you can grant or deny a user access to
cronwith the access control lists /etc/cron.allow and /etc/cron.deny, respectively. You might deny access to a user, for example, if his or her jobs were particularly disruptive to normal operation of the system.
As you can see, you need not forego your beauty sleep to keep your machine busy in
off-hours. Identify a job, define its schedule, capture the job in an appropriate
crontab, and start counting sheep. But before you doze off, let's look at the special
Working with crontabs
A crontab is simply a text file, which you can create with any number of UNIX editors. It can contain four kinds of lines: blank lines, comments, environment variable settings, and commands.
Blank lines and comments
Blank lines and spans of white space found in the file are ignored. Use both to keep your crontabs readable and well organized.
You can also use comments to document the timetable and purpose of each
job. To create a comment, simply start a new line with the octothorpe
Environment variables and commands
cron uses a shell to execute each
command. You can alter or customize the behavior of the shell through
Shell environment variables are easily set in a crontab. Simply type
VARIABLE with the name of the variable
value with a value. For example, the
specifies an ordered list of directories for the shell search path.
cron daemon predefines five environment
- The default value for PATH is /usr/bin:/bin.
- SHELL is preset to /bin/sh.
- LOGNAME is initialized to the crontab's owner's user name.
- HOME is set to the home directory of the crontab's owner, such as /home/joe.
- MAILTO is set to the name of the crontab's owner.
To override any of these defaults or to set any variable, simply set the appropriate environment variable in the crontab.
Of course, a crontab can have any number of command lines. Each command line specifies a frequency, a user name (only if the crontab is a system crontab), and a task to run. For example, the command:
5 0 * * * root find /tmp -type f -empty -delete
deletes all empty files and directories from /tmp (
find /tmp -type
f -empty -delete) once per day at 12:05 a.m.
5 0 * * *). The job runs as root
A system crontab command must specify a user name to run the task as a
specific user. (Hence, you would probably find the command above in,
say, /etc/crontab.) Per-user crontabs cannot specify a user name; as you
cron commands for a user always
run as the user. The omission of the user name is the only difference between
a system and user crontab.
As always, the devil is in the details. So, let's look at the many ways you can customize a timetable.
A cron timetable allows you to run jobs every minute or at a specific minute on a specific day. The parameters for scheduling are very flexible.
There are five fields—like "knobs"—that you can tweak to adjust frequency: minute, hour, day of month, month, and day of week. Table 1 summarizes what you can tune in each field.
Table 1. Scheduling options for cron jobs
|3||Day of month||1-31||Unlike minute and hour, day of month is not zero based.|
|4||Month||1-12||Month is not zero based, either. Additionally, instead of 1-12, you can use the first
three letters of each month's name, such as |
|5||Day of week||0-7||Both |
In addition to a name or number, you can use the asterisk
*) to specify "every." For instance, an asterisk
in the minute position indicates every minute of the day. (There are certainly
valid uses for such a high frequency, but be careful that such tasks are very
lightweight and do not run for protracted periods.)
You can also use lists of values, ranges, and steps (increments) to specify many, an inclusive range of values, and an alternating range of values, respectively. You can even combine lists and ranges. A list is a comma-separated set of values. A range is a starting and an ending value, inclusive, and an optional step value.
Let's look at some examples. Each row in Table 2 contains a
timetable and a description. A command is executed by
when the minute, hour, and month of year fields match the current time and if
both the day of month and day of week are restricted (that is, not
*) when at least one of the two fields matches
the current time.
Table 2. Example timetables for cron jobs
|Minute||Hour||Day of month||Month||Day of week||Description|
|Run the command at 1 a.m. on the 15th of January, March, May, July,
September, and November. For better legibility, you could have written the
|This schedule runs the command every 15 minutes.|
|This timetable executes its command every hour, on the half-hour, on Wednesdays and Fridays only. (You can use day names and month names in lists but not in a range.)|
|Run the command on the hour and half-hour from midnight to 5 a.m. and again between 7 p.m. and 11 p.m.|
|Run the command once per year at the stroke of midnight of 1 January.|
|Run the command at the stroke of midnight every Sunday. This is the equivalent of once per week.|
|Because the day of the month and day of the week are restricted, this command runs at 12:30 a.m. every Saturday and on the 10th, 20th, and 30th day of every month, except February.|
As you can see, you can express virtually any schedule using the five parameters
provided. As an added convenience, Vixie
provides shorthand for common schedules. Table 3
lists some of the choices.
Table 3. Helpful shorthand for common schedules
|Run the command whenever the machine reboots.|
|A shorthand for once per day.|
|A shorthand for once per week.|
|A shorthand for once per year. You can also write this as
|Run the command once per day at midnight. A synonym for this shorthand is
If you prefer to use the shorthand, replace the first five fields of the
cron command with the moniker. The following
command, albeit contrived, is much simpler to get at a glance.
@daily root /usr/local/scripts/clean_old_files.sh
Sample crontab commands
With the basics under your belt, let's look at some sample user crontab commands. You can certainly apply the same commands system-wide: Just remember to specify a user name after the day of week field (the fifth field) in all system crontab entries.
Create a personal crontab
To use a personal crontab, create a file for your commands with any text editor. By convention, personal crontab files are kept in ~/.crontab, but you can name the file anything you like.
PATH=/usr/bin:/bin:/usr/local/bin # # Every day, print and delete all temporary files whose names begin with '.#' @daily find $HOME -type f -name '.#*' -print -delete # # Every week, show me what is consuming space in my home directory @weekly du -sh $HOME
Submit the personal crontab to the crontab utility
After editing your file—say, ~/mycrontab—submit it to
cron with the aptly named
% crontab ~/mycrontab
View what's stored in cron
To see what's stored in
% crontab -l PATH=/usr/bin:/bin:/usr/local/bin # # Every day, print and delete all temporary files whose names begin with '.#' @daily find $HOME -type f -name '.#*' -print -delete # # Every week, show me what is consuming space in my home directory @weekly du -sh $HOME
Replace your crontab
You can use the
crontab utility to replace your
crontab at any time. Simply submit a new file or a revision of the same
file. To remove your crontab jobs, type
% whoami joe % crontab ~/mycrontab % crontab -l PATH=/usr/bin:/bin:/usr/local/bin ... % crontab -r % crontab -l crontab: no crontab for joe
Alternatives to cron
As useful as
cron is, there are a couple of alternatives
that you should be aware of.
If your system is often off or in hibernation—for example, if you use a
UNIX laptop—consider adding
to your system.
Anacron is similar to
cron in that it schedules jobs to run in the future;
run jobs even if the job's scheduled time has passed.
For example, if you scheduled a file-system backup to run Sunday but the system
is switched off from Friday to Monday,
runs the Sunday job as soon as the system is reactivated on Monday. In contrast,
cron merely checks whether a job is to run right
now; hence, if the system is off when the job is scheduled, the job doesn't run.
Anacron has far fewer scheduling options than
cron. It can only schedule jobs in whole-day
intervals, such as one, seven, or 30 days, but it's a better choice for jobs that
must run frequently and reliably.
Also, you must launch
anacron runs, it reads its own
configuration file consisting of pairs, where each pair is a job and its
frequency expressed in days. If a job hasn't run in its period,
runs the job and notes the time the job ran. When all jobs finish running,
Anacron is available on most Linux distributions,
but you can also easily download and build the source code yourself. Visit the
anacron project page
to get the latest release.
anacron primary configuration file can be found
in /etc/anacron. You can set environment variables just as you do with
cron, but its entries are simpler:
SHELL=/bin/zsh PATH=/usr/bin:/bin:/usr/local/bin # format: frequency delay name job 1 10 day-to-day daily.chores.sh
The first number is the period, so
1 means run once
every day. A
7 would mean run once per seven days,
and so on. The second number is the delay, which is the number of minutes to wait
anacron launches to start this job. The delay field,
if set to distinct values, prevents all jobs from starting at the same time. The name
day-to-day is just a helpful nickname. The rest of the line specifies the job;
here, the shell script daily.chores.sh, found in one of the directories in the named
path, runs every day.
Anacron has good documentation in the form of man pages,
and you can find very good tips on
anacron on the Web.
(Check out Rod Smith's Linux Magazine
article, which I edited in October 2007.)
ideal for UNIX road warriors or for any systems administrator who wants a bit of extra
Launchd: A modern alternative to cron
Cron is certainly a capable and venerable utility, as
evidenced by its widespread usage. Recent additions in Vixie
such as shorthand for
@reboot, make it even easier
to administer. However,
cron does have some
cronjobs are defined in crontab files, you cannot start and stop a
cronjob from the command line. Moreover, you cannot create an ad hoc job at the command line and submit it to the calendar.
Crondoes not enforce resource limits. A job can consume innumerable cycles and memory if run as root. You may, instead, want to damp down a job so that it cannot interfere with other
cronjobs and the overall quality of system operations.
Cronjobs adhere rigidly to a schedule. There is no way, for instance, to have a job launch only when an event occurs, such as the creation of a file.
- In a larger context, UNIX-like systems have many core components capable
of launching other programs on demand, including
inetd) for networking daemons, and
init, the progenitor of all system processes. Each core component has its own set of configuration files, making it difficult to know which components to tailor to make a change.
To address these shortcomings, Apple Computer created a unified launch facility, aptly
launchd, to start processes on boot, on
demand, and at specified intervals. In fact, launchd replaced
init and several
other system utilities used to boot and initialize the system) in Mac OS 10.4 Tiger.
cron on the system, though as a convenience
and because Vixie
cron has more flexible scheduling
options.) Indeed, the phenomenal boot speed of Mac OS X can be attributed to
launchd: It enumerates what to launch at boot but
executes the programs only when first needed.
launchd has been ported to FreeBSD but not
to other UNIX or Linux systems. However, various projects are actively implementing
the equivalent of
launchd, so a brief survey of its
features is necessary:
- Rather than create a job to poll a directory for new files,
launchdcan automatically monitor a directory for new files or monitor an empty directory for any files and launch your job on demand.
Launchddoes not poll; instead, it uses the kqueues facility to have the kernel alert it when a directory is changed. (Linux has a similar event facility called inotify, which will be covered in a separate developerWorks article in the coming months.)
- If specified,
chrootto send your job to a new directory. Pronounced "cha-root,"
chrootis a system call to change the directory that the forward slash (
/) and the root directory point to. Thus, if you use
chrootto send the file to /opt/root, all files outside /opt/root are inaccessible—after all, /opt/root is now /, the top-level directory of the file system—and all directories within /opt/root become top-level directories. You most commonly use
chrootto secure jobs so that code cannot wander into the larger file system to wreak havoc.
- You can set resource limits for a job. Resources you can constrain include memory, stack size, and the maximum number of open files.
- When a task is defined and loaded into
launchd, you can start and stop the job by name from the command line.
Launchd is made of three components: the
daemon itself; the launchctl utility used to add, alter, and remove jobs and
launchd; and one or more configuration files, where
each file defines one or more jobs. Given its origin on Mac OS X,
configuration files are simply properties files, which can be expressed as
Extensible Markup Language (XML).
Briefly, here is how you would use
launchd on Mac OS X—say,
to monitor a directory for incoming files and run a job on demand:
- Create a properties file to express the job and all its attributes.
You can use the Mac's Property Editor, or you can edit the XML by hand. In either case, the resulting file looks something like Listing 1.
Listing 1. A sample launchd job to monitor a file system directory for changes
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.example.processor</string> <key>OnDemand</key> <true/> <key>Program</key> <string>/Users/strike/bin/processor</string> <key>ProgramArguments</key> <array> <string>processor</string> </array> <key>WatchPaths</key> <array> <string>/Users/strike/data/incoming</string> </array> </dict> </plist>
In a nutshell, this file runs the utility script found in /Users/strike/bin/processor whenever the contents of the directory /Users/strike/data/incoming changes. Setting
OnDemandto True tells
launchdto start this job as needed. Save the file to ~/Library/LaunchAgents/com.example.processor.plist.
- Load the job into
% launchctl load ~/Library/LaunchAgents/com.example.processor.plist
If you want to verify the last operation or see your list of saved jobs, simply type
- To remove a job, again use launchctl with
% launchctl unload -w ~/Library/LaunchAgents/com.example.processor.plist
-wdo? It removes the job from
launchdcompletely. Without it, the job would re-load automatically at login (because the job is in the per-user collection of launch agents).
launchd man pages have lots of information, and if
you're a Mac OS X user, you can find any number of applications for
launchd. Hopefully, some clever developer will port
launchd more widely.
Using cron to your advantage
Get a few tips and tricks for using
cron, and discover
why this daemon and others like it may just be your best friends.
Tips and tricks
Here are some tips, tricks, and common pitfalls of
- Unlike the shell you use in a terminal window or for a shell script,
crondoes not expand environment variables in-place in crontab files. In other words, if you place the lines:
in a crontab, PATH is not set to what you expect. Instead, you must expand all variables manually, as in these lines:
However, because each cron command is executed by a shell, a command can refer to variable names. For example, if you place this command:
in your personal crontab (notice that the user name parameter is omitted in the line above), $HOME is expanded properly.
- Do not schedule compute-intensive tasks to begin at the same time, such as
@midnight. If possible, start such tasks independently throughout the wee hours of the morning, avoiding competition for resources.
- As mentioned above, the environment variable SHELL is set to /bin/sh by
default. If left unchanged, all commands in the crontab are interpreted
by /bin/sh. However, if you aren't familiar with /bin/sh and prefer
another shell, you can set SHELL and use your shell's syntax for
For example, if you set
SHELL=/bin/zsh, all commands can use the facilities of the Z shell, such as its advanced redirection operators:
SHELL=/bin/zsh @daily uptime > daily >> weekly
Here, the output of the command
uptimeoverwrites the file named daily (
>daily) and is appended to the file weekly (
- Use the access control lists (ACLs)—/etc/cron.allow and /etc/cron.deny—to
permit or preclude individual users from running
cronjobs. If you want to greatly limit access to
cronto just a few users, list those users' names in /etc/cron.allow. Anyone not named cannot submit a crontab using the crontab utility. However, if you want to grant wide access and prohibit just a handful of users from access to
cron, list the restricted users in /etc/cron.deny.
For example, if /etc/cron.allow looks like this:
any user other than Joe and Zelda is refused access to
% whoami strike % crontab ~/.crontab You (strike) are not allowed to use this program (crontab) See crontab(1) for more information
- To disable email reports from
MAILTO=""in the crontab.
- Again, do not use spaces in lists. Separate list values with commas. In Vixie
cron, do not use day names and month names in ranges.
- Read the documentation for your system's
croncarefully. Paths can differ, as can features and conveniences. To read about crontab file syntax, type
man 5 crontabat the command line. To read about the crontab utility, type
man 1 crontab. To find the options available for the
crondaemon itself, type
man 8 cronat the command line.
The systems administrator's best friend
Cron and its ilk are invaluable for systems
administration. If you find yourself performing the same task over and over
again, consider automation with
cron. Shell scripts
are often necessary to capture complex tasks with many steps, but you can also
achieve a great deal with a single command line run every so often.
Here are just a handful of ideas:
cronand your favorite database tools to create daily dumps. For example, the command
@daily joe mysqldump -pjoespwd accounts > $HOME/backups/accounts.`date +%F`.sql
dumps the database named accounts daily to a file. The embedded date command (
`date +%F`) ensures that the file name is unique, as in accounts.2008-08-07.sql. The command runs as joe, so Joe's password is specified with
-p. This command could also simply appear in Joe's own crontab, because his MySQL credentials are required for the dump.
- The locate subsystem indexes all files on the system and stores the
full path to each file in a database. You can then query the database
from the command line to instantly find files. Of course, you can
search for files on demand with
find, but you must wait as it crawls the file system each time it runs.
To make locate effective, though, you must index the file system on a regular basis, because files come and go all the time. This is a perfect application for
0 0,12 * * * root updatedb
This crontab entry runs
updatedb, the locate update utility, twice per day.
- Another obvious task well suited to automation with
cronis copying files from a master to its many slaves.
Rsyncis a modern utility that distributes and synchronizes collections of files across multiple systems. Many Web masters combine
rsyncto push a master copy of the Web site to each server in the farm.
@midnight www rsync -avz /var/www/site slave1:/var/www
At midnight each night,
rsyncexactly copies (
-avz) /var/www/site to /var/www on slave1.
Use the command-line
|) to send the output of a task to one or more people on your staff.
@weekly root df --print-type --local -h |& mail -s "Weekly df report" andy bob
Here, the output of
dfis mailed weekly to users Andy and Bob to monitor disk usage.
Whether you run your own UNIX system or a system for hundreds of users, automating
maintenance tasks saves time, reduces errors, and keeps machines humming through
all hours of the night.
Cron is a pivotal part of automation
on UNIX systems, and with a little imagination, you can make your computer work for
you instead of against you.
Cron can help you work smarter, not harder. Now, won't you
Learn more about the history of
To discover the specifics of your
man 5 crontabin any shell window.
Read more about
- Check out additional UNIX tips and tricks from the developerWorks site.