Scheduling tasks with cron





Last Updated on 09/21/2019 by dboth

so you don’t have to stay up late

Being a SysAdmin has its advantages but it also has some challenges. I have no time to spare in the evenings to run commands and scripts that need to be run during off-hours. There are many tasks that need to be performed off-hours when no one is expected to be using the computer or, even more importantly, on a regular basis at specific times.

I don’t want to have to get up at oh-dark hundred to start a backup or major update, so I use two service utilities that allow me to run commands and programs, tasks, at predetermined times. The cron and at services give SysAdmins the ability to schedule tasks to be run at a time or times in the future.

The cron service can be used to schedule tasks on a repetitive basis, such as daily, weekly, or monthly. This article will provide an introduction to the cron service and how to use it.

cron

I use the cron service to schedule obvious things like regular backups that occur every day at 2:00AM. I also do a couple less obvious things. All of my many computers have their system times, that is the operating system time, set using NTP – the Network Time Protocol. NTP sets the system time; it does not set the hardware time which can drift. I use cron to set the hardware time using the system time. I also have a Bash program I run early every morning that creates a new “message of the day” (MOTD) on each computer that contains information such as disk usage that should be current in order to be useful. Many system processes use cron to schedule tasks as well. Services like logwatch, logrotate, and rkhunter, all use the cron service to run programs every day.

The crond daemon is the background service that enables cron functionality.

The cron service checks for files in the /var/spool/cron and /etc/cron.d directories, and the /etc/anacrontab file. The contents of these files define cron jobs that are to be run at various intervals. The individual user cron files are located in /var/spool/cron, and system services and applications generally add cron job files in the /etc/cron.d directory. The /etc/anacrontab is a special case that will be covered further on in this article.

Using crontab

Each user, including root, can have a cron file. By default no file exists, but using the crontab -e command as shown in Figure 1 to edit a cron file creates them in the /var/spool/cron directory. I strongly recommend that you not use a standard editor such as vi, vim, emacs, nano, or any of the many other editors that are available. Using the crontab command does not only allow you to edit the command, it also restarts the crond daemon when you save and exit from the editor. The crontab command uses vi as its underlying editor because vi is always present on even the most basic of installations.

All cron files are empty the first time you edit it so you must create it from scratch. I added the job definition example in Figure 1 to my own cron files just as a quick reference. Feel free to copy it for your own use.

In Figure 1 the first three lines set up a default environment. Setting the environment to that necessary for a given user is required because cron does not provide an environment of any kind. The SHELL variable specifies the shell to use when commands are executed. In this case it specifies the Bash shell. The MAILTO variable sets the email address to which cron job results will be sent. These emails can provide the status of backups, updates, or whatever, and consist of the output from the programs that you would see if you ran them manually from the command line. The last of these three lines sets up the PATH for this environment. Regardless of the path set here, however, I always like to prepend the fully qualified path to each executable.

# crontab -e
SHELL=/bin/bash
MAILTO=root@example.com
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
# For details see man 4 crontabs
# Example of job definition:
#.---------------- minute (0 - 59)
 # |  .------------- hour (0 - 23)
 # |  |  .---------- day of month (1 - 31)
 # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
 # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
 # |  |  |  |  |
 # *  *  *  *  * user-name  command to be executed
 # backup using the rsbu program to the internal 4TB HDD and then 4TB external
 01 01 * * * /usr/local/bin/rsbu -vbd1 ; /usr/local/bin/rsbu -vbd2
 # Set the hardware clock to keep it in sync with the more accurate system clock
 03 05 * * * /sbin/hwclock --systohc
 # Perform monthly updates on the first of the month
 # 25 04 1 * * /usr/bin/dnf -y update 

Figure 1: The crontab command is used to view or edit the cron files.

There are several comment lines that detail the syntax required to define a cron job. I think that they are mostly self-explanatory so I will use the entries in Figure 1 as examples, then add a few more that will show you some of the more advanced capabilities of crontab files.

The line shown in Figure 2, below, runs my self-written Bash shell script, rsbu, to perform backups of all my systems. This job is kicked off at 1 minute after 1AM every day. The splat/star/asterisks (*) in positions 3, 4, and 5 of the time specification are like file globs for those time divisions; they match every day of the month, every month, and every day of the week. This line runs my backups twice; once to backup onto an internal dedicated backup hard drive, and once to backup onto an external USB hard drive that I can take to the safe deposit box.

01 01 * * * /usr/local/bin/rsbu -vbd1 ; /usr/local/bin/rsbu -vbd2

Figure 2: This line in my /etc/crontab runs a script that performs backups for my systems.

The line shown in Figure 3 sets the hardware clock on the computer using the system clock as the source of an accurate time. This line is set to run at 3 minutes after 5AM every day.

	03 05 * * * /sbin/hwclock --systohc

Figure 3: This line sets the hardware clock using the system time as the source.

The last cron job in Figure 1 has been commented out, but I had been using it to perform a dnf or yum update at 04:25AM on the first day of each month. I have commented that one out so it no longer runs.

Now let’s do some things that are a little more interesting than the basics I have shown you so far. Suppose you want to run a particular job every Thursday at 3PM. Something like that would look like Figure 4.

00 15 * * Thu /usr/local/bin/mycronjob.sh

Figure 4: This line runs myjob.sh every Thursday at 3PM.

Another requirement might be to run quarterly reports after the end of the quarter. The cron service has no option for “The last day of the month,” so we use the first day of the following month. This requirement does assume that the data needed for the reports will be ready at the time the job is run.

02 03 1 1,4,7,10 * /usr/local/bin/reports.sh

Figure 5: This cron job runs quarterly reports on the first day of the month after the quarter ends.

Figure 6 is an example of running a job at one minute past every hour between 9:01AM and 5:01PM.

	01 09-17 * * * /usr/local/bin/hourlyreminder.sh

Figure 6: Sometimes you only want to run jobs during normal business hours.

I have encountered situations where running a job every 2, 3, or 4 hours is needed. That can be accomplished by dividing the hours by the desired interval, such as */3 for every three hours, or 6-18/3 to run every three hours between 6AM and 6PM. The other time divisions can also be divided like this. The expression */15 in the minutes division means to run the job every fifteen minutes.

 */15 08-18/2 * * * /usr/local/bin/mycronjob.sh

Figure 7: This cron job runs every five minutes between 0800 and 1858.
Note that the division expressions must result in a remainder of zero (0) in order for the job to run. That means that in Figure 7 the times that the job runs will be 08:05, 08:10, 08:15, etc, 10:05, 10:10, etc, during all of the even numbered hours but not during any odd numbered hours. The job will not run at all from 7PM through 7:59AM.

I am sure you can extrapolate many other possibilities based on these few examples.

Limiting cron access by users

Due to possible misuse of cron by non-root users that might cause system resources such as memory and CPU time to be swamped, the SysAdmin can limit user access to cron. To prevent all non-root users from having access to cron, simply create the empty file /etc/cron.allow. Only users listed in that file are allowed access to create cron jobs.

The root user cannot be prevented from using cron.

While preventing regular non-privileged users from using cron themselves, it may be necessary to run sron jobs for them. Their cron jobs can be added to the root crontab. “But wait!” You say. “Doesn’t that run those jobs as root?” It does not necessarily have to. The user name shown in the comments for the job definition specifications in Figure 1 is for when the root crontab is used to run jobs for another user. In that case the program is run as the specified non-root user and does not have root privileges.

cron.d

The directory /etc/cron.d is where some applications such as SpamAssassin and sysstat install cron files. Because there is no spamassassin or sysstat user, these programs need a place to locate cron files so they are placed in /etc/cron.d.

The /etc/cron.d/sysstat file in Figure 8 contains cron jobs that relate to SAR – System Activity Reporting. These cron files have the same format as a user cron file.

# Run system activity accounting tool every 10 minutes
*/10 * * * * root /usr/lib64/sa/sa1 1 1
# Generate a daily summary of process accounting at 23:53
53 23 * * * root /usr/lib64/sa/sa2 -A 

Figure 8: The sysstat package installs the /etc/cron.d/sysstat cron file to run programs for the System Activity Reporting tool, SAR.

The sysstat cron file has two lines that perform tasks. The first line runs the sa1 program every ten minutes to collect data which is stored in special binary files in the /var/log/sa directory. Then every night at 23:53, the sa2 program is run in order to create a daily summary.

Scheduling tips

Some of the times I have set in the crontab files for my various systems seem rather random and to some extent they are. Trying to schedule cron jobs can be challenging especially as the number of jobs increases. I usually only have a couple tasks to schedule on each of my own computers so it is a bit easier than some of the production and lab environments I have worked.

One system for which I was the SysAdmin usually had around a dozen cron jobs that needed to run every night and an additional three or four that had to run on weekends or the first of the month. That was a challenge because if too many jobs ran at the same time, especially the backups and compiles, the system would run out of RAM and then nearly fill the swap file which resulted in system thrashing while performance tanked so that nothing got done. We added more memory and were able to do a better job of scheduling tasks. Adjusting the task list included removing one of the tasks which was very poorly written and which used large amounts of memory.

The crond service assumes that the host computer runs all the time. What that means is that if the computer is turned off for a period of time and cron jobs were scheduled for that time, they will be ignored and will not run until the next time they are scheduled. This might cause problems if the cron jobs that did not run were critical. So there is another option for running jobs at regular intervals.

anacron

The anacron program performs the same function as crond but it adds the ability to run jobs that were skipped if the computer was off or otherwise unable to run the job for one or more cycles. This is very useful for laptops and other computers that get turned off or put in sleep mode.

As soon as the computer is turned on and booted, anacron checks to see whether configured jobs have missed their last scheduled run. If they have, those jobs are run immediately, but only once no matter how many cycles have been missed. For example, if a weekly job was not run for three weeks because the system was shut down while you were away on vacation, it would be run soon after you turn the computer on, but it would be run once not three times.

The anacron program provides some easy options for running regularly scheduled tasks. Just install your scripts in the /etc/cron.[hourly|daily|weekly|monthly] directories, depending on how frequently they need to be run.

How does this work? The sequence is simpler than it first appears.

First, the crond service runs the cron job specified in /etc/cron.d/0hourly as seen in Figure 9.

# Run the hourly jobs 
SHELL=/bin/bash 
PATH=/sbin:/bin:/usr/sbin:/usr/bin 
MAILTO=root 01 * * * * root run-parts /etc/cron.hourly 

Figure 9: The contents of /etc/cron.d/0hourly cause the shell scripts located in /etc/cron.hourly to run.

The cron job specified in /etc/cron.d/0hourly runs the run-parts program once per hour and the run-parts program runs all of the scripts located in the /etc/cron.hourly directory.

The /etc/cron.hourly directory contains the 0anacron script which runs the anacron program using the /etdc/anacrontab configuration file shown in Figure 10.

# /etc/anacrontab: configuration file for anacron # See anacron(8) and anacrontab(5) for details. SHELL=/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root # the maximal random delay added to the base delay of the jobs RANDOM_DELAY=45 # the jobs will be started during the following hours only START_HOURS_RANGE=3-22 #period in days delay in minutes job-identifier command 1 5 cron.daily nice run-parts /etc/cron.daily 7 25 cron.weekly nice run-parts /etc/cron.weekly @monthly 45 cron.monthly nice run-parts /etc/cron.monthly

Figure 10: The contents of /etc/anacrontab file runs the executable files in the cron.[daily|weekly|monthly] directories at the appropriate times.

The anacron program runs the programs located in /etc/cron.daily once per day; it runs the jobs located in /etc/cron.weekly once per week, and the jobs in cron.monthly once per month. Note the specified delay times in each line that helps prevent these jobs from overlapping themselves and other cron jobs.

Instead of placing complete Bash programs in the cron.X directories, I install them in the /usr/local/bin directory which allows me to run them easily from the command line. Then I add a symlink in the appropriate cron directory, such as /etc/cron.daily.

The anacron program is not designed to run programs at specific times. Rather, it is intended to run programs at intervals that begin at the specified times such as 3AM (see the START_HOURS_RANGE in Figure 10) of each day, on Sunday to begin the week, and the first day of the month. If any one or more cycles are missed, then anacron will run the missed jobs one time as soon as possible.

Final thoughts

I use most of these methods for scheduling tasks to run on my computers. All of those tasks are ones that need to run with root privileges. I have seen only a few times when users had a real need for any type of cron job. One example I have seen of user cron jobs is for a developer to kick off a daily compile in a development lab.

It is important to restrict access to cron functions by non-root users. However there are circumstances when it may be necessary for a user to set tasks to run at pre-specified times and cron can allow users to do that when necessary. SysAdmins realize that many users do not understand how to properly configure these tasks using cron and the users make mistakes in the configuration. Those mistakes may be harmless but, more often than not, they can cause problems for themselves and other users. By setting functional policies that cause users to interact with the SysAdmin those individual cron jobs are much less likely to interfere with other users and other system functions.

It is possible to set limits on the total resources that can be allocated to individual users or groups, but that is an article for another time.

Resources

The man pages for cron, crontab, anacron, anacrontab, and run-parts all have excellent information and descriptions of how the cron system works.