Unusual cron job settings
cron jobs can be set up to run at various times, such as:
- X minutes past every hour
- Y minutes past hour Z
- X,Y and Z minutes past hours A,B and C
- Every Monday at a particular time
- The Nth day of each month at a particular time
Some cron systems can also be set to run jobs:
- 3 times per hour (at 0, 20 and 40 minutes past)
- 4 times per hour plus an offset (eg: at 3, 18, 33 and 48 minutes past)
However, there are some things that standard cron configurations can't cope with, such as:
- the first Monday of each month
- the last Friday of each month
- the 14th of each month provided it's a Tuesday
Note: It may at first seem simple to set up a job to run on the 14th of the month when it's a Tuesday, but it turns out that if you do specify this, the job runs both every Tuesday and also on the 14th of the month. It's the isolated instance of a logical OR between timings, when all others are a logical AND.
34 12 14 * Tue command.sh
Anyway, back to the topic…
How do you set up a cron job to run on the first Monday of each month?
There are two pretty much equally simple ways of going about this (and probably several others which are not so simple):
- Set up a job to run every Monday, and check whether it's the first one in the month
- Set up a job to run on the first seven days of each month, and check whether the day is a Monday
For example (assuming the job should run at 03:45 on the appropriate day) either of the following will work:
45 3 * * Mon test `date +%e` -lt 8 && command.sh 45 3 1-7 * * test `date +%u` -eq 1 && command.sh
Note that I used "date +%u" to get the numerical day of the week (1=Monday, 7=Sunday) instead of "date +%a" (for Mon, Tue, Wed, etc) to avoid any internationalisation problems - you want the command to work on a machine whose system language is French or German just the same as it works in English.
Now for some more complicated examples…
How do you set up a cron job to run on the last day of each month?
This is not so simple, because there's no easy way of knowing which date in a month is the last one.
In this case, we run a check every day to find out whether the current month is the same as tomorrow's month:
45 3 * * * test `date +%m` -eq `date +%m -d tomorrow` || command.sh
So, every day, if the month number equals the month number on the next day time, we do not run the command, otherwise we do.
If you want it slightly more efficient (don't bother checking for the first 21 days of each month), you can do:
45 3 22-31 * * test `date +%m` -eq `date +%m -d tomorrow` || command.sh
How about the last Friday of each month?
In this case, we run a check every Friday to find out whether the current month is the same as the month in seven days' time:
45 3 * * Fri test `date +%m` -eq `date +%m -d +7days` || command.sh
So, every Friday, if the month number equals the month number in 7 days' time, we do not run the command, otherwise we do.
How about the last working day (weekday) of each month?
Once again, we have no idea which are the final seven days of a month, however in this case we also need to allow for any day, Monday to Friday, being the final one of the month, but not run on Monday (for example) if Tuesday is also still in the same month.
So, we check on Monday to Thursday whether the following day is still in the same month, and do nothing if it is. If it isn't, then this is clearly the last day of the month.
On Friday we need to check whether the following Monday is in the same month (and do nothing if it is) because we don't care about the weekends.
45 3 * * Mon-Thu test `date +%m` -eq `date +%m -d tomorrow` || command.sh 45 3 * * Fri test `date +%m` -eq `date +%m -d +3days` || command.sh
How do you set up a cron job to run on every Tuesday when it's the 14th of the month?
By now this should be obvious - use either of:
45 3 * * Tue test `date +%e` -eq 14 && command.sh 45 3 14 * * test `date +%u` -eq 2 && command.sh
Backticks
Some people might change `…` into $(…) - feel free to use this syntax if you prefer it.
Go up
Return to main index.