How to Run a cron Job Every Two Weeks / Months / Days
Posted on In Linux, TutorialWe may want to run some jobs for every two weeks/months/days… under some situation such as backing up for every other week. In addition, we may add more complex rules for running jobs, e.g. run a command when the load of the server is higher than a certain level. With the help of the shell programming language we can easily achieve this goal.
Table of Contents
Basics of the crontab
Crontab file controls how and what to run by cron. The crontab line has a format as follows:
.---------------- 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 ...
| | | | |
* * * * * command to be executed
To add a cron job for your current user, run
$ crontab -e
And edit the crontab file by adding/deleting lines. Check the crontab man page for more details.
The cron job is run as a piece of shell code. /bin/sh
is the shell by default. You may change it to some other shells like bash by adding a like like SHELL=/bin/bash
at the beginning of the crontab file.
Method 1: use crontab extensions
crontab provides some extensions to support this: ranges can include “steps” like /2
. 1-9/2
is the same as 1,3,5,7,9
. This can be the easiest method if the job is intended to be run every two N in a range such as N is “day” and the range is “days in a month”. Check the crontab man page for more details about ranges and steps of crontab.
An example.
To run the command every two months at 1:00 on the first day of the month, the crontab is
0 1 1 */2 * command to be executed
But please be aware that the every two N here is not exactly every two N. For days, it is every two days in a month. For months, it is every two months in a year. If you need to make sure your cron job is run exactly every two N, check the other methods.
Method 2: use a test statement to control whether to really run the command
The command executed for a cron job is a piece of shell code. So you can make the command run every day/week/month while use a test statement to control whether to really run the command.
Let’s take an example to illustrate the idea. Now, we want to run a job every 2 days. As there are months having 31 days, some jobs are not run exactly every 2 days if we use method 1 above. We can have a cron job as follows to make sure it runs exactly every 2 days (86400 seconds) at 1:00.
0 1 * * * < $((($(date +%s) / 86400) % 2)) == 0 > && /path/to/your/command
Here, the shell script < $((($(date +%s) / 86400) % 2)) == 0 > && /path/to/your/command
is run every day. But your command is run only when $((($(date +%s) / 86400) % 2)) == 0
. That is when the number of days since 1970-01-01 00:00:00 UTC is divisible by 2.
With the help of date
, we can make make test statements. Let’s take another example, run a job exactly every 5 months starting from March of 2016. The cron tab entry can be
0 1 1 * * < $(((($(date +%Y) - 2016) * 12 + $(date +%m) - 3) % 5)) == 0 > && /path/to/your/command
Only when the number of months since March 2016 is divisible by 5, the command is run.
Method 3: use a shell script with its state saved on disk
The idea is to invoke a shell script every day/week/month and the shell judges whether to run the job. The key idea here is that the shell uses a file to mark its state.
The shell code:
#!/bin/bash
# a file marking the state on disk
mark_file=$HOME/.job-run-marker-1
# check whether the job run last time it is invoked
if [ -e $mark_file ] ; then
rm -f $mark_file
else
touch $mark_file
exit 0
fi
# job command is here
The script will not find $mark_file on the first run, so it will create it and exit. On the second run the script will remove $mark_file and then proceed to execute the job command. For the third run, it is the same as the first run. So if this script is run weekly by cron, the job command will run every two weeks.
You can extend the shell with more complex logic like storing the last run date/time in the $mark_file or check more system information like the CPU/mem/disk load.
An example is as follows.
We want to back up Xen DomU VMs for every two weeks. We create a script /home/share/bin/xen-bak. The beginning part of this script is like what we list above.
The line for the job is as follows.
0 2 * * 2 /home/share/bin/xen-bak
The backup command will run at 2:00 for every other Tuesday.
Wouldn’t 0 2 * * 2 just run it 2am EVERY Tuesday?
I think what your looking for is:
0 2 * * 2/2
or
0 2 * * Tue/2
You are right. The most updated instruction is at the beginning of the post.
The “poor man’s” solution here works actually — the invoked script is invoked every Tue but it records its state and does nothing every next time it is invoked.
aaah I see, cool thanks man :-)
Your explanation defeats the purpose of CRON. I could implement my own logic in code (every two weeks) and I only need cron to run every minute … So please correct your script.
Hi Eric, I have a request to make the job run in each alternative monday usually twice a month….
What’s the instruction for that??
This is easy to do in your crontab file with no external scripting:
0 2 * * tue [ `expr $(date ‘+\%U’`) % 2` -eq ‘0’ ] && /home/share/bin/real-xen-bak
This will only work if your “date” command understands the “%U” format, which gives the week-of-the-year. The “date” command on most *NIX systems will understand this, as “date” uses the C-library’s “strftime” function which specifies “%U” as the format specifier for week-of-year.
Interesting script.
The most easy method as far as I find is the ranges-based one like */2 supported by cron. Please check the Update at the beginning of the post.
I was wondering if there was a way to schedule something, say every 5 months, that changes the month when it crosses a year boundary. For example I have the following cron expression :
0 1 1 15 3/5 ? *
Which, when I run it starting at the beginning of the year gives me these fire times :
1. Sunday, March 15, 2015 1:01 AM
2. Saturday, August 15, 2015 1:01 AM
3. Tuesday, March 15, 2016 1:01 AM
4. Monday, August 15, 2016 1:01 AM
5. Wednesday, March 15, 2017 1:01 AM
Notice that if it were truly scheduling every 5 months, starting on the 3rd month, I would expect it to schedule in March 2015, August 2015, January 2016, June 2016, etc
Is this not the correct cron expression, or is there something I’m missing?
Hi Quenten, that’s a good question. The ‘*/5’ for months in crontab means every 5 months in a year.
For your purpose, you may try:
I also updated the post with more details. Please check out.
hi, how do we do it if we want it to run every alternate Tuesday at 0800?
0 8 * * 2/2
thanks,
You may use
0 8 * * 2 [[ $((($(date +%s) / 604800) % 2)) == 0 ]] && /path/to/your/cmd
It is invoked every Tuesday at 0800. However, your command will be executed only if the number of weeks since epoch is even.
I would like to run every 15days then how to write it.
Brilliant. Too bad we are tie with epoch and hv to be restrict to even, so if there is 5 Tuesday in a month, it will only run on the 2nd and 4th week. But its good enough at the moment :)
This will work with all Centos or only certain version? we are running on version 7.
p/s – how do you get the the 604800? its too small for minutes and too little if for seconds
thanks,
A more complex test condition may be used if you want to run it on 2nd and 4th Tuesdays in a month.
I believe this works on modern cron including those from CentOS 7. But please test it before deploying it into production.
604800 is 60 * 60 * 24 * 7. It is the number of seconds in a week.
Everyone,
I also have a script to run every 2nd and 4th Tuesday of each month for 2017. I use the following entries (starting June 13, 2017 to Dec 26, 2017). I know it is long, but it is easier to read and without the need for any date calculation.
Note: make sure that you do not specify the day of week (2); otherwise, cron will run on
BOTH on a specify day of the month AND on Tuesday of EVERY week.
I use this URL to validate
this URL to calculate: http://cron.schlitt.info/index.php?cron=30+3+13+6+*&iterations=10&test=Test
30 3 13 6 * myscript.sh
30 3 27 6 * myscript.sh
30 3 11 7 * myscript.sh
30 3 25 7 * myscript.sh
30 3 8 8 * myscript.sh
30 3 22 8 * myscript.sh
30 3 12 9 * myscript.sh
30 3 26 9 * myscript.sh
30 3 10 10 * myscript.sh
30 3 24 10 * myscript.sh
30 3 14 11 * myscript.sh
30 3 28 11 * myscript.sh
30 3 12 12 * myscript.sh
30 3 26 12 * myscript.sh
I also found another method for the same time period June 13 to Dec 26 of 2017, but prefer the 1st method as it is more clear to me. The 2nd method below requires calculate whether a Tues will be on even or odd week of the month.
30 3 * 6-8,11,12 2 [[ $(expr `date +\%W` \% 2) = 0 ]] && myscript.sh
30 3 * 9,10 2 [[ $(expr `date +\%W` \% 2) = 1 ]] && myscript.sh
Interesting. But it seems the crontab entries need to be refreshed each year if Tuesday is a hard requirement.
Thanks for sharing
How to run cron after 5th of every month and every alternate day at 12 am
How to run cron after 5th of every month and every alternate day at 12 am
You may consider a crontab to be invoked every alternate day at 12am with a “test statement” to check whether it is after 5th day.
how to run cron Tuesday night and run on every two weeks?
86400 seconds is every day, not every two days.
`% 2` for every two days.
* */3 * * tue runSomething.here
To run some thing here every 3 days always on tue* day, is it correct?
as from crontab manual.
So, a rule like
`0 0 */3 * 2 your_command`
*should* run at 0 o’clock every 3 days if it is Tuesday from the rule.
But the implementation may be different. I did not test it.
what should be the cron syntax to run a job twice a month ?
A cron job like this may work:
0 0 1,15 * * /path/to/your/command
Every day 1 and day 15 of a month, the command will run at 00:00.
@ Eric ma,
I would like to run the cron every 15days interval I tried as below
00 21 */15 * *
But the result didn’t not satisfying the 15days interval condition.
Nxt at 2020-07-16 21:00:00
then at 2020-07-31 21:00:00
then at 2020-08-01 21:00:00
then at 2020-08-16 21:00:00
then at 2020-08-31 21:00:00
This can work for one month but in next Month it again triggers from 1st day of the month. Can you help to provide the condition to satisfy the requirement?
Sir, I have to write crontab:
Latest two day data must be present remaining past data will be clean the temp
How I have to do that
I would like to run the cron every 15days interval I tried as below
00 21 */15 * *
But the result didn’t not satisfying the 15days interval condition.
Nxt at 2020-07-16 21:00:00
then at 2020-07-31 21:00:00
then at 2020-08-01 21:00:00
then at 2020-08-16 21:00:00
then at 2020-08-31 21:00:00
This can work for one month but in next Month it again triggers from 1st day of the month. Can you help to provide the condition to satisfy the requirement?
Hello Basheer,
Can you please let me know if you able to find the solution for your condition.
I think a test statement is an easy way to implement.
Example: Let’s say a command needs to be executed every Thursday.
0 0 1-7,15-21 * * [ `date +\%u` = 4 ] && /path/to/command
Cron job pattern for alternate thursday
Trying to understand the syntax. If I wanted this to run every 85 days, is it just as simple as changing the 2 to 85?
0 1 * * * && /path/to/your/command