Introduction
When managing a computer, we may want to automate some tasks to run in certain periods or at the same time on each day/week/month. On a desktop, we may schedule update checks or virus scans. On a server, it's not uncommon for a myriad of checks and clean up routines to be scheduled to ensure applications are running optimally.
In this article, we will look at the cron
program. This utility is a task scheduler for Unix-like systems. After going over cron basics, we'll look at the crontab
command to manage our scheduled tasks.
What is Cron? What is a Crontab?
To master cron
and scheduling, it helps to have a grasp of various but similar terminology used.
Cron is the program that schedules scripts or commands to run at user-specified times. A cron expression is a string that details the schedule to trigger a command. A cron table is a configuration file containing the shell commands in each line preceded by a cron expression.
Here's an image with a system crontab that references two external scripts:
Generally, cron tables look like this:
<cron-expression> <command>
<cron-expression> <command>
When your computer first starts up, cron searches for all crontabs in system-configured directories. The directory varies from OS to OS but it's typically /etc/crontab
for special system-wide crontabs and a local directory for the user who's logged in. These are both loaded into memory.
The cron program wakes up every minute and checks the crontab in memory to see if any commands need to be run at the current minute. It executes all scheduled commands and sleeps again.
There are two methods by which the cron jobs can be scheduled:
- Edit the
crontab
directly
We can view the cron jobs we have scheduled by running this command:
$ crontab -l
If we would like to add or edit a cron job, we can then use this command:
$ crontab -e
This is the preferred method to edit crontabs because it selects the user crontab and not the system one, and it also catches syntax errors.
- Copying the scripts to the
/etc/cron.*
directories
If scheduling the scripts for accurate time slots is not required, the scripts can also be moved inside certain pre-built cron schedule folders, for the crontab to pick them up for execution. These predefined directories that act as placeholders include:
Location | Execution Schedule |
---|---|
/etc/cron.hourly/ | Once every hour |
/etc/cron.daily/ | Once per day, everyday |
/etc/cron.monthly/ | Once per month, every month |
/etc/cron.weekly/ | Once per week, every week |
The users can copy their scripts to the appropriate directories depending on which frequency they need to be run. The crontab file present in /etc/crontab
contains the cron expressions defined for each directory and it checks every minute if the time is right for the scripts are to be executed:
Note that scripts placed in these special folders are system-wide cron jobs and not user-specific ones.
Creating a Cron Expression
Each entry of the crontab contains a cron expression, a user name, and the command to be executed separated with white spaces or tabs:
* * * * * user-name command-or-file-to-be-executed
# <-----------> <-------> <---------------------------->
# Cron
# Expression
Note: The user-name
column is used when editing the system-wide crontab. A user-specific crontab does not need it because that info is already known.
The 5 asterisks (* * * * *
) in the cron expression can be substituted with numbers. Their positions indicate their value:
* Position | Description | Allowed numeric values |
---|---|---|
1 | Minute | 0-59 |
2 | Hour | 0-23 |
3 | Day of Month | 1-31 |
4 | Month | 0-12 |
5 | Day of Week [0 represents Sunday & Saturday represents 6] | 0-6 |
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
Alongside numbers, there are special characters we can use when editing a crontab:
Characters | Description |
---|---|
* | Defining this will run the command for each time frame. For example, * defined under the minute column, will execute the script every minute |
, | To repeat a task in multiple different time frames, commas can be used. For example, to run a script every 10 minutes, the minute column can be given as 0,10,20,30,40,50 |
/ | An alternative, simpler version of ",". To run a script every 10 minutes, the minute column can be given as */10 |
- | Specifies a range of values. To run a script every minute for the first 10 minutes, the expression in the minute column can be given as: 0-10 |
That's a lot of options to understand, it might be best to show how they work with some examples:
- Here's how to run
echo "hello there!"
on the "4th day of every week" (i.e. on Thursday) at 12:10 hours:
10 12 * * 4 root echo "hello there!"
- And here's a more complicated example where we save disk usage every 20 minutes on the first 10 days of the last three months of the year:
*/20 * 1-10 10,11,12 * df -h >> /tmp/diskusage
Cron expressions can be overwhelming at first sight. There are numerous tools available online to simplify the creation of expressions; crontab.guru
is one of the widely popular tools available online at crontab.guru/.
Let's use crontab.guru to check if our second express is valid: crontab.guru/#*/20_*_1-10_10,11,12_*.
Hands-on Guide: Creating a Cron Job to Email Disk and Memory Usage
In an IT department, system administrators and other operators frequently monitor computer resources such as memory and disk size. Crontab is commonly used to ensure monitoring scripts are run continuously.
We are going to create a cron job that monitors disk and RAM usage using Watchmon. If either metric is above a certain threshold, we will get an email to alert us. We'll put this script in a cron job that runs every minute.
The following demo was tested on Ubuntu 20.04.1 LTS
. This example is configured to send an email to a Gmail account, you may need to tweak your configurations for other email providers.
- You first need to install watchmon. Follow their README to learn how to set it up:
$ git clone https://github.com/datawrangl3r/watchmon
$ cd watchmon
$ bash setup.sh
- The script will start the cron process, install http://www.mutt.org/, a command-line SMTP client, to send emails. Once installed, use your text editor to the
mutt.rc
file in your home directory:/home/user/mutt/mutt.rc
.
Edit your file so it looks like this, changing the template data with your email:
set ssl_starttls=yes
set ssl_force_tls=yes
set imap_user = "[email protected]"
set imap_pass = "PASSWORD"
set from="[email protected]"
set realname="Your Name"
set folder = "imaps://imap.gmail.com/"
set spoolfile = "imaps://imap.gmail.com/INBOX"
set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
set header_cache = "~/.mutt/cache/headers"
set message_cachedir = "~/.mutt/cache/bodies"
set certificate_file = "~/.mutt/certificates"
set smtp_url = "smtps://[email protected]:[email protected]:465/"
set move = no
set imap_keepalive = 900
- Since Google doesn't allow its services to be accessible by less secure apps, we need to enable access for the email account to be used in the SMTP settings. Visit https://myaccount.google.com/security, and toggle the less secure app access to ON, as shown in the gif below:
- Now that our scripts and email account configurations are ready, we can set up our crontab. Edit your crontab by invoking:
$ crontab -e
Now enter the corresponding cron expression and path to the executable with arguments. Note that the path on your machine will differ from what is shown below:
* * * * * /mnt/c/Users/sathy/Documents/datawrangler/watchmon/watchmon.sh -t=40 [email protected]
This can be configured as shown below:
The cron utility makes sure to execute the script every minute and as a result, an email is sent from the machine to the recipients until the disk space or memory of the machine is cleared.
Cron Jobs and Dealing with Failures
Although crontabs are very powerful, they can't alert the user if an underlying job is not triggered or the scheduled executable encounters an error. The logs for each job run can be found in the /var/log/syslog
file. Be sure to review your logs after activities are scheduled.
Aside from cron and command errors, many crontabs are plagued by human errors. When setting up cron jobs, here are some common reasons why your cron job may not run as you'd expect it to:
-
The scripts don't have the execute permission for it. Those executables that are to be run as cron jobs should have the permission as
755
i.e.rwx-rw-rw
. The cron utility can only execute scripts if the user has executable permissions for it. -
The crontab is syntactically correct but the wrong path was used for the jobs. It's important to specify the absolute path to the executable and the command itself. Relative paths need to be avoided at all costs.
-
The command or script is not being run with the necessary environment variables to work. In these cases, make sure that the script you run can set up the required env vars when running as a cron job.
Conclusion
In this article, we have looked at the cron program, cron expressions, and crontabs. We used the crontab
command to list and edit cron jobs. Crontabs are some of the best tools for Unix-like systems to automate repetitive tasks. What would you schedule with a cron job?