CRON job to run on the last day of the month
Possibly the easiest way is to simply do three separate jobs:
55 23 30 4,6,9,11 * myjob.sh
55 23 31 1,3,5,7,8,10,12 * myjob.sh
55 23 28 2 * myjob.sh
That will run on the 28th of February though, even on leap years so, if that's a problem, you'll need to find another way.
However, it's usually both substantially easier and correct to run the job as soon as possible on the first day of each month, with something like:
0 0 1 * * myjob.sh
and modify the script to process the previous month's data.
This removes any hassles you may encounter with figuring out which day is the last of the month, and also ensures that all data for that month is available, assuming you're processing data. Running at five minutes to midnight on the last day of the month may see you missing anything that happens between then and midnight.
This is the usual way to do it anyway, for most end-of-month jobs.
If you still really want to run it on the last day of the month, one option is to simply detect if tomorrow is the first (either as part of your script, or in the crontab itself).
So, something like:
55 23 28-31 * * [[ "$(date --date=tomorrow +\%d)" == "01" ]] && myjob.sh
should be a good start, assuming you have a relatively intelligent date
program.
If your date
program isn't quite advanced enough to give you relative dates, you can just put together a very simple program to give you tomorrow's day of the month (you don't need the full power of date
), such as:
#include <stdio.h>
#include <time.h>
int main (void) {
// Get today, somewhere around midday (no DST issues).
time_t noonish = time (0);
struct tm *localtm = localtime (&noonish);
localtm->tm_hour = 12;
// Add one day (86,400 seconds).
noonish = mktime (localtm) + 86400;
localtm = localtime (&noonish);
// Output just day of month.
printf ("%d\n", localtm->tm_mday);
return 0;
}
and then use (assuming you've called it tomdom
for "tomorrow's day of month"):
55 23 28-31 * * [[ "$(tomdom)" == "1" ]] && myjob.sh
Though you may want to consider adding error checking since both time()
and mktime()
can return -1
if something goes wrong. The code above, for reasons of simplicity, does not take that into account.
There's a slightly shorter method that can be used similar to one of the ones above. That is:
[ $(date -d +1day +%d) -eq 1 ] && echo "last day of month"
Also, the crontab entry could be update to only check on the 28th to 31st as it's pointless running it the other days of the month. Which would give you:
0 23 28-31 * * [ $(date -d +1day +%d) -eq 1 ] && myscript.sh