1. Overview
The Cron tool is well-known for executing scheduled jobs on Linux machines. It comprises several components:
- Cron daemon, which executes the jobs
- crontab command that we can use to schedule jobs
- crontab configuration files where Cron entries are stored
In this tutorial, we’ll see examples of Cron jobs that execute periodically within a given time range.
2. The Cron Entries Format
A Cron entry consists of five space-delimited date-time fields and a shell command. Here are the date-time fields and their allowed values:
- Minute (0-59)
- Hour (0-23)
- Day of the month (1-31)
- Month (1-12) or the month’s name
- Day of the week (0-7) or the day’s name
Importantly, in a Cron entry, the fields appear in the exact order specified, meaning the minute comes first, then the hour, and so on.
Further, we can create or edit Cron entries with the crontab -e command.
3. Setting Periods With Ranges
In Cron, a range is a set of two values separated by a hyphen. We can use ranges to define the period that we want to execute our job. Furthermore, we can set a range in any date-time field.
Let’s create a job that runs every minute from 9:00 to 16:59, Monday to Friday:
* 9-16 * * 1-5 echo 'Hello World'
Here, we’ve set a range in the hour field. The minute, the day of the month, and the month fields are set to the wildcard (*) character.
Moreover, we’ve set the range 1-5 to the day of the week field. Value 1 is for Monday and value 5 is for Friday. As a result, the echo command will run every minute, from 9:00 to 16:59, from Monday to Friday, and every month.
In fact, we can verify this by checking the system log that the Cron daemon uses during job execution:
$ cat /var/log/syslog | grep CRON | tail -n 3
Nov 2 13:42:01 CRON[155913]: (user) CMD (echo 'Hello World')
Nov 2 13:43:01 CRON[155936]: (user) CMD (echo 'Hello World')
Nov 2 13:44:01 CRON[155961]: (user) CMD (echo 'Hello World')
As we can see in the output above, Cron indeed executes our job every minute.
4. Setting Step Values
To execute a job every couple of minutes, we can set a step value of two (2):
*/2 9-16 * * * echo 'Hello World'
We set step values as numbers after a slash (/) character. Consequently, the given entry will run the job every two minutes, from 9:00 to 16:59 for every day and month. Again, we can verify this by checking the logs:
$ cat /var/log/syslog | grep CRON | tail -n 3
Nov 2 14:12:01 CRON[156048]: (user) CMD (echo 'Hello World')
Nov 2 14:14:01 CRON[156055]: (user) CMD (echo 'Hello World')
Nov 2 14:16:01 CRON[156058]: (user) CMD (echo 'Hello World')
As expected, our job runs every two minutes.
In addition, we can use a step value together with a range:
30-35/2 * * * * echo 'Hello World'
The above expression runs the echo command every two minutes, from minutes 30 through 35 past the hour, every hour, day, and month. Let’s verify:
$ cat /var/log/syslog | grep CRON | tail -n 3
Nov 2 15:30:01 CRON[156286]: (user) CMD (echo 'Hello World')
Nov 2 15:32:01 CRON[156290]: (user) CMD (echo 'Hello World')
Nov 2 15:34:01 CRON[156297]: (user) CMD (echo 'Hello World')
Indeed, our job ran within the defined time range.
5. Using Lists of Values
In addition to time ranges, Cron entries support lists of comma-separated values.
Continuing our earlier example, if we want to exclude 11:00 and 14:00 from the range 09:00 to 17:00, we can do it by enumerating the exact hours we want in a list:
30-35/2 9,10,12,13,15,16,17 * * * echo 'Hello World'
Thus, our job will run every two minutes, between minutes 30 and 35 of the hour, from 9:00 to 17:00 excluding 11:00 and 14:00. Moreover, a list can also contain one or multiple ranges:
30-35/2 9-11,15-16 * * * echo 'Hello World'
Here, our job will run only within the 09:00 to 11:59 and 15:00 to 16:59 time ranges. In other words, we’ve excluded 13:00 and 14:00.
6. Complex Time Ranges
Sometimes we might need more than one Cron entry to define our time range. This can happen when a time range involves part of a time unit, like half a month.
6.1. Parts of Months
Let’s say that we want to execute our job every day at midnight, from October 15th until November 20th:
0 0 15-31 10 * echo 'Hello World'
0 0 1-20 11 * echo 'Hello World'
The time range we want to define deals with a part of October and a part of November. This means that we can’t use a single entry, because the day ranges are specific to months, and will get tangled up.
So, even though the time range is continuous, the solution is to break it into two Cron entries. The first entry defines the period from the 15th to the 31st of October (10), while the second defines the period from the 1st to the 20th of November (11).
6.2. Parts of Days
Furthermore, to make things more complex, we may want to start our job at a specific hour. For example let’s say that we want our job to run every hour, starting at 17:00 on October 15th and stopping at 18:00 on November 20th:
0 17-23 15 10 * echo 'Hello World'
0 * 16-31 10 * echo 'Hello World'
0 * 1-19 11 * echo 'Hello World'
0 0-18 20 11 * echo 'Hello World'
For this scenario, we created four Cron entries. The two extra entries deal with the first and the last days because only parts of them are included in the time range. So, each entry defines the execution of the job at the 1st minute of every hour, in the following order:
- on the 15th of October (10), after 17:00
- from the 16th to the 31st of October (10)
- from the 1st to the 19th of November (11)
- on November (11) 20th, until 18:00
In other words, when only a part of a time unit is involved, we may have to create more than one Cron entry.
7. Conclusion
In this article, we examined examples of how to execute a Cron job periodically in a given time range. We saw how we can define ranges, lists of values, and steps. Finally, we learned how to deal with scenarios where parts of time units are involved.