How to Use Cron to Automate Linux Jobs on Ubuntu 20.04

January 26th, 2022
How to Use Cron to Automate Linux Jobs on Ubuntu 20.04

Job scheduling applications are designed to carry out repetitive tasks as defined in a schedule based on time and event conditions. In this article you will learn how to install and start using Cron - the most popular Linux workload automation tool that is widely used in Linux community.

What is Cron?

Cron is a Linux job scheduler that is used to setup tasks to run periodically at a fixed date or interval. Cron jobs are specific commands or shell scripts that users define in the crontab files. These files are then monitored by the Cron daemon and jobs are executed on a pre-set schedule.


To follow this guide, you should have:

  • A machine with Ubuntu 20.04 installed and root access privileges.
  • Basic Linux command-line experience.

Install Cron

Most often Cron is installed to your Ubuntu machine by default. In case it is not there, you may install it yourself.

Update your system’s local package list:

sudo apt update

And install the newest version of cron. The following command also updates Cron to the latest version, if you already have it installed:

sudo apt install cron

Congrats! You now have the latest version of Cron installed on your machine.

Understand How Cron Works

Cron jobs are commands or shell scripts that are referenced in crontab files. These files are loaded into memory and monitored for pre-set actions that need to be taken. Cron wakes up every minute to examine all stored crontabs and see if any command needs to be executed in the current minute.

Additionally, Cron monitors the modification time of each crontab file on the system. If any crontab has been changed, it is automatically reloaded into memory. This way Cron doesn’t need to be restarted when a crontab modification is made.

💡 Pro Tip: Cron assumes that your system is running continuously 24/7, so it is perfectly suited for servers that must be online all the time. However, cron cannot execute tasks that were scheduled for a time when your system was offline. As this may be an issue for desktop computers, use anacron instead to schedule jobs at the specified intervals as closely as machine uptime permits.

Setup Your First Cron Job

Every Cron job should be specified in a crontab – a configuration file, also known as the Cron table. Create your first crontab by using the crontab command with an option -e which stands for editing, but is also used for crontab instantiation:

crontab -e

crontab instantiation

If you are creating crontab for the first time, you will be asked to select your default text editor. Select your preferred editor [1 – 4] and press ENTER to open a new crontab with your selected text editor. The newly created crontab is populated with some useful comments:

default crontab comments

Let’s now add a new Cron job to the bottom of this file:

* * * * * echo “Hello World at $(date)” >> $HOME/greetings.txt

Every minute this Cron task runs the command echo “Hello World at $(date)” >> $HOME/greetings.txt. This command retrieves the current date, stuffs it into the “Hello World […]” string and appends the string to a greetings.txt file that is in your home directory. If the doesn’t exist yet, it will be created.

Save the file and exit. Wait a few minutes and check the greetings.txt file that should have been created in your home directory and populated with relevant data:

tail ~/greetings.txt

A file populated by multiple cron jobs

As you can see, every minute Cron executes the given task: current time is stuffed into the “Hello World […]” string and appended to the bottom of the file.

Understand Cron Job Syntax

Every Cron task is written in a Cron expression that consists of two parts: the time schedule and the command to be executed. While the command can be virtually any command that you would normally execute in your command-line environment, writing a proper time schedule requires some practice.

The Cron task syntax consists of 6 arguments separated by spaces. First 5 arguments describe the execution time, while the last argument is a command or a full path to a shell script that is going to be executed by the default shell:

[minute] [hour] [day of month] [month] [day of week] [command]

Commands are executed by Cron when the minute, hour and month fields match the current time, and when at least one of the day fields – either day of month, or day of week – match the current time. The allowed values are these:

Field Allowed values
minute 0-59
hour 0-23
day of month 1-31
month 1-12 (or names: JAN - DEC)
day of week 0-6 (or names: SUN - SAT)

There are also some special characters that you can use to further specify the execution time:

Special field value Description Example
Asterisk An asterisk represents every allowed value (first to last). * (run every hour, month, etc.)
Range A range consists of two numbers separated by a hyphen. 0-5 (run from 0th to 5th hour, month, etc.)
List A list is a set of numbers or ranges separated by commas. 0,1,2,3,4,5 (run from 0th to 5th hour, month, etc.)
Step A step is used in conjunction with ranges or asterisks. */2 (run every second hour, month, etc.)
Name A name can be used with month or day of week fields. Names are case insensitive. Jan, Feb, Mar (run every January, February, and March)
Special string A special string can be used instead of the first five arguments. @reboot, @weekly (run every time at startup, and once a week)

You may play with execution time targeting rules by using the website which is a great place to deepen your understanding and double check whether you defined the execution time right.

💡 Pro Tip: the @reboot runs once at the cron daemon startup. It may happen before some other system daemons are started due to the boot order sequence of the machine. This may cause some of the commands not working properly.

Manage Crontab Configuration Files

Crontab, also known as the Cron table, is a list of environment settings and Cron commands that are stored in a file and used by the cron daemon to execute tasks on a scheduled basis. There are different types of crontab files available, so let’s review them one by one.

Manage User-owned Crontab Files

Users have their own crontab files that are stored in the spool area and named after the user’s account. Each crontab is executed as the user who owns the crontab. You can check for user-owned crontab files by listing all files in the spool directory:

ls /var/spool/cron/crontabs

list spool crontabs

As you can see, there are currently 3 crontab files created for users named root, user1 and user2.

Crontab configuration files of the individual users should not be edited directly, but rather by using the crontab command. The crontab program verifies and installs the crontab file itself without a need for root privileges.

You have already used the crontab -e command that creates a new crontab for a user or allows editing an existing crontab. You may check the contents of your existing crontab file by using the following command:

crontab -l

list crontabs

As you can see, there is a single active Cron task that we have added before.

If you would like to remove your crontab file to terminate all your scheduled tasks, use the following command:

crontab -r

Manage System-wide Crontab Files

System-wide crontab files are created upon cron installation and mainly used by system services. Packages like dpkg, sysstat and many others depend on cron and use it to schedule specific tasks. In a system’s crontab there is a user field that is used to execute given tasks.

System crontabs must be owned by root and cannot be edited by any other user. There is no crontab command to edit these files, so they can be accessed directly by the system administrator. Let’s now access the main system crontab:

vim /etc/crontab

system-wide crontab

As you can see, we have SHELL and PATH environment variables defined. There are also four Cron tasks that are specific to Debian-based operating systems. These tasks are going to use run-parts utility to execute all scripts that are put in cron.hourly/, cron.daily/, cron.weekly/, cron.monthly/ on an hourly, daily, weekly and monthly basis respectively.

Any script in above mentioned directories must pass the run-parts verification. A script must be executable, owned by root, and not be writable by group or others. Let’s now create a simple bash script that is going to log Bitcoin prices every hour:

vim /etc/cron.hourly/get_bitcoin_price


bitcoin_price=$(jq -r '.data.amount' <<< ${result})
echo "Bitcoin price is $bitcoin_price USD on $(date)" >> $HOME /bitcoin_prices.txt

Our script queries a Coinbase API, gets Bitcoin price information in JSON, parses it with the jq program to cherry-pick the price and logs it along with the current datetime to bitcoin_prices.txt file in the /root home directory.

A script you put into /etc/cron.daily/ directory can be any script you like to be executed on an hourly basis. Just don’t forget to write a path to your preferred shell at the top (#!/usr/bin/bash) and make your script executable:

chmod u+x /etc/cron.daily/get_bitcoin_price

You may double check your script to make sure it is executable, owned by root, and are not writable for group and others:

list script permissions

It seems our script is well-configured and ready to be executed by Cron on an hourly basis.

There is also a /etc/cron.d/ directory in Debian-based systems. Cron treats all files in this directory in the same way as the main /etc/crontab file, except that crontab files put into /etc/cron.d/ do not load environment variables. It is only recommended to create separate crontab files in the /etc/cron.d/ directory if you need that extra isolation.

Manage Cron Output

The output of cron jobs – both STDOUT and STDERR – is automatically sent to the crontab owner’s local mailbox by default. Each user’s mailbox is a standard text file that is stored in the /var/mail/ directory. You may access it directly or through the mail command, if mailutils package is installed.

You may change the default behavior by specifying MAILTO directive in your crontab file. For instance, if you want the output of your Cron tasks to be sent to a user john, you should add the following line at the top of your crontab:


A user’s local mailbox is different than an email sent over the Internet. If you want to send an email outside of your server, you may do so by specifying the MAILTO directive accordingly:

Of course, if you are sending an email through the Internet network, you must have some type of an SMTP server – Sendmail, Postfix, etc – running on the same host or on your LAN.

Manage Cron Logs

Cron logs are stored in the /var/log/syslog global logging file by default. If you want to see your Cron activity, filter the syslog file to find CRON service activity:

grep CRON /var/log/syslog

Filter CRON logs

Crontab file activity is also logged. If you want to see it, just filter the syslog file accordingly:

grep crontab /var/log/syslog

Filter crontab logs

It is not very convenient to filter the global log file every time. A better practice is to configure rsyslog utility to copy cron logs in a separate file. To do so edit the following file:

vim /etc/rsyslog.d/50-default.conf

You need to uncomment the following line:

cron.* /var/log/cron.log

Save the file and restart rsyslog service for the configuration to come into effect:

systemctl restart rsyslog

After a while you should see a new cron.log file created in the /var/log/ directory with your Cron activity logs inside:

cat /var/log/cron.log

A newly created separate cron log

If you haven’t changed syslog configuration, every log entry follows a standard pattern:

[timestamp] [hostname] [app_name] [log_message]

You can see the log rows follow this pattern, for instance:

Jan 14 15:12:01 ubuntu-sandbox CRON[345431]: (root) CMD (echo "Hello World at $(date)" >> $HOME/greetings.txt)

Let’s dissect these fields:

  • timestamp=Jan 14 15:12:01 – indicated the date and time when the message was generated on the system;
  • hostname=ubuntu-sandbox – indicates the system that sent the message
  • app_name=CRON[345431] – indicates the name and process id of the application that sent the message
  • log_message=(root) CMD (echo “Hello World at $(date)” >> $HOME/greetings.txt) – the action that was taken. In this case CRON informs us that the following root user’s cronjob was executed: echo “Hello World at $(date)” >> $HOME/greetings.txt.

💡 Pro tip: You are not going to see logging information about scripts that have been executed in the /etc/cron.{hourly, daily, weekly, monthly}/ directories, unless those scripts explicitly direct the output to the cron.log file.

Monitor Cron Jobs With Cronitor

It may be a hassle to go back and forth through your Cron logs, especially if you have hundreds of jobs running on your system. Luckily, there are Cron job monitoring tools available in the market that help you monitor your cron jobs and get insights in real time.

One such tool is Cronitor that captures the status, metrics, and output of every Cron job. With tools like Cronitor you may easily name and organize each job, as well as ensure that the right people are alerted if something happens.

Monitoring 5 Cron jobs with Cronitor is free of charge and it is easy to get started. After you install Cronitor CLI and configure your API key, run the following command to scan your system crontabs for all active Cron jobs:

cronitor discover

You will be prompted to name your Cron jobs and, after you are done, Cronitor will immediately start monitoring them. You can check the status of your Cron jobs and configure alerts on your Cronitor dashboard:

Cronitor monitoring panel


Cron is a powerful tool that is often used by system administrators to automate otherwise tedious tasks. After completing this guide, you now have a well-rounded understanding of how to use Cron to schedule tasks on your Linux systems. For any further information, feel free to check the official Cron documentation page.

Helping engineers learn 💡 about new technologies and ingenious IT automation use cases to build better systems 💻

Join Cherry Servers Community

Get monthly practical guides about building more secure, efficient and easier to scale systems on an open cloud ecosystem.

We use cookies to ensure seamless user experience for our website. Required cookies - technical, functional and analytical - are set automatically. Please accept the use of targeted cookies to ensure the best marketing experience for your user journey. You may revoke your consent at any time through our Cookie Policy.