Cron: the Job Scheduler in Linux/Unix

December 7, 2021

Cron is a job scheduler utility in Linux/Unix. It is used to execute commands (called cronjobs) at a given schedule without any human intervention. I can use it, for example, to backup and update my computer every Sunday or reboot my servers at the start of every month.

1. Installation and Early Preparation

Many distributions install it by default. But for barebone distributions like Archlinux, you might need to install it.

1.1. Installation of Cron

Archlinux based distributions:

~$ sudo pacman -S cronie

Fedora based distributions:

~$ sudo dnf install cronie

Debian based distributions:

~$ sudo apt install cron 

1.2. Activation of Cron

Now, activate the cron daemon using systemd.

Archlinux and Fedora based distributions:

~$ sudo systemctl enable cronie.service
~$ sudo systemctl start cronie.service

Debian based distributions:

~$ sudo systemctl enable cron.service
~$ sudo systemctl start cron.service

Now that we have set up cron, we will be learning about creating cronjobs.

2. Creation of Cronjobs

Cronjobs are created using the following crontab command:

~$ crontab -e

The above command opens a text file using the editor specified by the VISUAL or EDITOR environment variables. If you have not specified the variable, it uses the Vi editor. And if your system does not have Vi editor installed, it might throw another error saying it. In that case, you will need to supply EDITOR as well:

~$ EDITOR=nano crontab -e

Here, in the text file, we write our cronjobs. Your output might look like this:

# Chronological table of program loadings                                       
# User: johndoe
# source: https://wiki.archlinux.org/title/cron

# mm  hh  DD  MM  W /path/progam
  21  01  *   *   * /usr/bin/systemctl hibernate
  30  06  *   *   1 /usr/bin/ubdatedb

In the above example, each line corresponds to a single cronjob. And empty lines and comment lines (lines starting with a #) are ignored. These cronjobs are written in special syntax which is described below.

Note: The crontab -e command is used to create cronjobs for the user who executed it. To create cronjobs for the root user, use the sudo.

~$ sudo crontab -e

As stated above, you might need to supply the EDITOR variable also. These root user's cronjobs will have administration-level permissions. Hence, they will be able to execute commands like system update.

2.1. Cronjob Syntax

Each cronjob has 6 fields separated by space. The first five fields are time and date fields:

| Fields | Allowed Values | | --- | --- | | Minute | 0-59 | | Hour | 0-23 | | Day of Month | 1-31 | | Month | 1-12 (or JAN-DEC) | | Week | 1-7 (or MON-SUN; 0 can be used for SUN as well) |

Source: man 5 crontab

The sixth field is the command to be run. By default, this command is run by /bin/sh shell.

The above description was all about basic cronjob expression. Now, we learn more about it through examples. There are some advanced formats as well which will be clear after we go through these examples.

2.2. Cronjob Examples

The simplest Example will be to execute the command once every minute. In the example given below, a star means all possible values (just like a star in bash).

* * * * * echo $SHELL > /tmp/shell.txt

Currently, I use the following cronjobs to back up my PC using rsync once every week (Monday at 6 AM).

#min hr day month w cmd
0  6  *   *   MON /home/ajay/.my_scripts/rsync.sh -b

Similarly, I execute the updatedb command once every hour. It helps me in using locate command in my launcher.sh script to launch any files.

#min hr day month w cmd
0  *  *   *   * /usr/bin/ubdatedb

At the same time, the above cronjob example is the same as the following with **@hourly**.

#min hr day month w cmd
@hourly /usr/bin/ubdatedb

Just like above, we also have @yearly, @annually, @monthly, @weekly, @daily, and @reboot. They mean:

   @reboot    :    Run once after reboot.
   @yearly    :    Run once a year, ie.  "0 0 1 1 *".
   @annually  :    Run once a year, ie.  "0 0 1 1 *".
   @monthly   :    Run once a month, ie. "0 0 1 * *".
   @weekly    :    Run once a week, ie.  "0 0 * * 0".
   @daily     :    Run once a day, ie.   "0 0 * * *".

Moreover, I reboot a few of my servers in the night once every month (At 12:00 AM, on day 1 of the month) using

#min hr day month w cmd
0 0 1 * * /usr/bin/systemctl reboot

Further, we can use /n to create a periodic interval of n. For example, to execute a cronjob once every 2 hours we will be using

#min hr day month w cmd
0 */2 * * * /bin/cmd

Another great example will be to execute a cronjob at the end of every month (at 12 AM). In the example given below a dash specifies range. So 28-31 means anything between 28 and 31. :

#min hr day month week
00 00 28-31 * * test $(date -d tomorrow +%d) -eq 1 && /bin/cmd

At the same time, We can also merge these syntaxes and create a complex cronjob schedule. For example, to create a cronjob every 1.5 hours:

#min hr day month week0 0-23/3 * * * /bin/cmd30 1-23/3 * * * /bin/cmd

2.3. Advanced Crontab Examples:

Example 1.

#min hr day month w cmd
10 11 12-17 * WED /bin/cmd

Meaning: At 11:10 AM, between days 12 and 17 of the month, and on Wednesday.

Example 2.

#min hr day month w cmd
34-56/2 * * * * /bin/cmd

Meaning: Here, /2 creates an interval of 2. So, this syntax means cronjob at every 2nd minute from 34 through 56 i.e. at minutes 34, 36, 38,...,56.

Example 3.

#min hr day month week
10,20 1,3 * * *

Meaning: Here, commas are used to create a list of numbers. So, the above syntax means "At minutes 10 and 20 past hour 1 and 3". We can use a comma with a dash to create other ranges as well such as "0-4,8-12".

Extra Information: You can also check on Crontab.guru - The Online Cron Schedule Expression Editor - to create more complex cron schedules. You can also use it to test your syntax before putting them in crontab -e.

After adding these cronjobs, you can edit them in the future using the same crontab -e command. The previous text file will be opened. You just need to change the texts in it. You can add new lines for new cronjobs as well.

Now that we have created some cronjobs, we will be learning how to do some manipulation like removing/listing them, or allowing/denying it for certain users.

3. Listing Cronjobs

Command crontab -l lists the current user's all existing cronjobs.

~$ crontab -l

Sample Output:

# comment
* * * * * echo hello > /tmp/test

Similarly, use sudo to list the root user's existing cronjobs

~$ sudo crontab -l

4. Removing Cronjobs

Command crontab -r is used to remove cronjobs

~$ crontab -r

For the root user,

~$ sudo crontab -r

5. Manupulating Cronjobs for Other Users

This requires administration-level permission. All of the above-mentioned commands can be executed as other users using the -u flag. For example, if a user named 'admin' with administration level permissions wants to list all the cronjobs for another user named 'another_user', he can use the following command:

~# crontab -u another_user -l

Similarly, he can use crontab -u another_user -e and crontab -u another_user -r for editing and removing cronjobs respectively.

The admin user can also ban certain users from using crontab by putting their username in file /etc/cron.deny. Similarly, he can put certain users in file /etc/cron.allow to allow only these users to use crontab.

6. A Little Warning: $SHELL and $PATH

Sometimes, you might see PATH and SHELL environment variables are defined in the crontab -e as well:

PATH=/home/ajay/.my_scripts:/bin:/usr/bin:/usr/local/bin
SHELL=/bin/bash
* * * * * echo hello > /tmp/test.txt

The rationale behind the declaration is that crontab uses /bin/sh shell instead of the default shell of the user who created it. You can verify this using the following cronjob:

#min hr day month week
* * * * * echo $SHELL > /tmp/path.txt

This might lead to unexpected behavior - you, for example, might be using bash's specific commands not available in /bin/sh (symlinked to /bin/dash in Ubuntu) and end up with errors.

To know more about symlinks, read my article on it.

Similarly, it ignores the PATH variable of the user. Because of this reason, in all of my above examples, I am using the full path to command (/bin/cmd instead of just cmd).

Likewise, to send notification over notification-daemon such as notify-send, we need to set DISPLAY and DBUS_SESSION_BUS_ADDRESS environment variables as well. Learn how to do it over here.

7. Anacron - Icing on the Cake

Unlike cron, anacron does not assume that your system is running continuously. And that is useful in the following cases:

1. Your laptop/desktop computer shuts down/hibernates/sleeps while a cronjob's execution was underway.

2. The computer is off while a cronjob was supposed to get executed.

Next time, the computer starts the cronjob is executed.

For more, see How To Use Anacron In Linux.

8. Wrapping Up

Cron (or Cronie) is a powerful tool to schedule your job. It is used widely in industries. Over time many new variations have popped up such as **fcron, dcron**, **cronwhip, vixie-cron, scron** for people with special needs. Alternatively, you can also use systemd-timer for setting up a minimal system - a default setting in Archlinux.

Before I go I like to thank you to stay up to this point. If you still have any queries, you can read them in Archwiki, man 8 cron, man 1 crontab, man 5 crontab, man 5 anacrontab, man 8 anacron or you can also put them in the comment section below. And also I have tried my best to make sure that there is not any mistake in the article. But, if there are still some mistakes, please notify me using the comment section.