Ever wondered how to run a cron job on the last day of the month?
To view your cron jobs, type crontab -l on the command line. Or to create a new one or edit an existing one, crontab -e is the command.
The basic cron syntax consists of 6 pieces, 5 time descriptors and the command to run or execute at the appointed time.
Minute Hour Day Month DayOfWeek /Path/CommandToRun
The first day is easy, 0 0 1 * * /Path/CommandToRun (* means any.)
At 0 minutes after 0 hour on day 1 of any month and any day of the week execute /Path/CommandToRun
Simple enough, you can tweak the day and time to suit your needs, all except for the last day of any particular month because the last day of the month can be 28, 29, 30 or 31 depending on Pope Gregory’s magical formula for keeping Easter the right side of Christmas, yet early enough in the year so that it’s not so warm that your Easter Egg melts.
So we use these very same numbers in our crontab as a range, like this 28-31
Obviously 0 0 28-31 * * /Path/CommandToRun isn't going to solve our problem, it will work correctly on the last day of the month 12 times a year but another 29 times a year it will trigger wrongly, (30 times on leap years), and that simply isn’t good enough.
A really useful property that the last day of the month has, is that it is always followed by the first day of the next month. So what is required is a tomorrow test. We test whether tomorrow is the 1st and if it is, then our end of month cron job runs, otherwise nothing happens.
By using && /Path/CommandToRun after the test, the /Path/CommandToRun will only be executed if the tomorrow test equals ‘1’ (True).
The complete solution is,
0 0 28-31 * * test $(date +\%d --date tomorrow) = ‘01’ && /Path/CommandToRun
TL;DR - Conclusion.
At 0 minutes after 0 hour on days 28 to 31 of any month and any day of the week AND tomorrow’s date is 01, execute /Path/CommandToRun
The sharp eyed may have noticed the '\' in the final solution, this is because cron treats ‘%’ as a special character and to use it literally you must escape it.