Classic Shell Scripting - Arnold Robbins [199]
The facility that provides for running jobs at specified times consists of the cron daemon started at system startup, and the crontab command for management of a simple text file that records when jobs are to be run: see the manual pages for cron(8) and crontab(1). You can list your current job schedule with crontab -l (lowercase L), and start an editor to update it with crontab -e. The editor chosen is determined by the EDITOR environment variable; depending on the system, crontab may refuse to run if that variable is not set, or it may simply start ed.
The crontab file (see the manual pages for crontab(5)) supports shell-style comments, so we find it helpful to start it out with comments that remind us of the expected syntax:
$ crontab -l
List the current crontab schedule
# mm hh dd mon weekday command
# 00-59 00-23 01-31 01-12 0-6(0=Sunday)
...
In the first five fields, instead of a single number you can use either a hyphen-separated inclusive range (e.g., 8-17 in the second field to run hourly from 08:00 to 17:00), or a comma-separated list of numbers or ranges (e.g., 0,20,40 in the first field to run every 20 minutes), or an asterisk, meaning every possible number for that field. Here are some sample entries:
15 * * * * command Run hourly at quarter past the hour
0 2 1 * * command Run at 02:00 at the start of each month
0 8 1 1,7 * command Run at 08:00 on January 1 and July 1
0 6 * * 1 command Run at 06:00 every Monday
0 8-17 * * 0,6 command Run hourly from 08:00 to 17:00 on weekends
* * *
Warning
Although POSIX says that blank lines are ignored, some commercial versions of crontab do not tolerate blank lines, actually deleting a crontab file that contains them! We recommend avoiding them in your own crontab files.
* * *
Commands in the crontab file run with a few environment variables already set: SHELL is /bin/sh, and HOME, LOGNAME, and sometimes, USER, are set according to values in your entry in the passwd file or database.
The PATH setting is sharply restricted, often to just /usr/bin. If you are used to a more liberal setting, you may either need to specify full paths to commands used in the crontab file, or else set the PATH explicitly:
0 4 * * * /usr/local/bin/updatedb Update the GNU fast find database nightly
0 4 * * * PATH=/usr/local/bin:$PATH updatedb Similar, but pass PATH to updatedb's children
Any output produced on standard error or standard output is mailed to you, or in some implementations, to the user specified by the value of the MAILTO variable. In practice, you more likely want output redirected to a log file and accumulated over successive runs. Such a crontab entry might look like this:
55 23 * * * $HOME/bin/daily >> $HOME/logs/daily.log 2>&1
Log files like this continue to grow, so you should do an occasional cleanup, perhaps by using an editor to delete the first half of the log file, or tail -n n to extract the last n lines:
cd $HOME/logs Change to log-file directory
mv daily.log daily.tmp Rename the log file
tail -n 500 daily.tmp > daily.log Recover the last 500 lines
rm daily.tmp Discard the old log file
Just be sure to do this at a time when the log file is not being updated. Obviously, this repetitive process can, and should, itself be relegated to another crontab entry.
A useful alternative to a cumulative log file is timestamped files with one cron job log per file. For a daily log, we could use a crontab entry like this:
55 23 * * * $HOME/bin/daily > $HOME/logs/daily.`date +\%Y.\%m.\%d`.log 2>&1
cron normally changes percent characters in commands to newlines, but the backslashes prevent that unusual behavior.
You can easily compress or remove old log files with the help of the find command:
find $HOME/logs/*.log -ctime +31 | xargs bzip2 -9 Compress log files older than a month
find $HOME/logs/*.log -ctime +31 | xargs rm Remove log files older than a month
* * *
Tip
To keep your crontab file clean and simple, put