Run Cronjob on Specific Day of the Month, Adjust for Weekends

cronschedulingscripting

I have a cronjob that runs a script on the 20th day of the month at 6 AM:

0 6 20 * * /opt/example.sh

This works as intended, but I'd like to adjust this, so the script is executed earlier, if the 20th falls on a Saturday or Sunday. For example:

On February 20 2021, the script is scheduled to run, however this is a Saturday, so instead it is executed on Friday the 19th.
Likewise, on February 20 2022, the script is scheduled to run, yet this is a Sunday, so instead it is executed on Friday the 18th.

I was not able to identify any options or hacks to accomplish this with cronjob itself. I was hoping to find some trick to use with the usable alternative single values (i.e. SUN for Sunday in the crontab).

I assume this needs to implemented in the script itself.

For example I could run it on the 18th and delay the execution (sleep) within the script, until the 20th unless the weekend is reached. This seems very error prone to me. Alternatively, I had the idea to schedule the execution for the 18th, 19th and 20th and check the date in the script, if it's within my intentions to be executed or not.

Is there any way to implement this with cron itself?

Best Answer

I would create a script runsometimes.sh with the contents:

#!/bin/bash
if [ $(date +%d) -eq 18 && $(date +%A) == "Friday" ] ; then/opt/example.sh ; exit ; fi
if [ $(date +%d) -eq 19 && $(date +%A) == "Friday" ] ; then /opt/example.sh ; exit; fi
if [ $(date +%d) -eq 20 ] ; then /opt/example.sh ; fi

and make sure cron tests it everyday: 0 6 * * * runsometimes.sh

Some notes:

  • The script that i wrote is longer then it should be, you can shrink it into 1 "if-then-fi" by combinining conditions. I just wrote it like this because it's easier to read
  • "Good style" dictates that i should play with else instead of exit, but again: I think this is easier to read
  • I quickly wrote the answer without testing it, test it before you use it !
  • I assume that your system uses a English locale (again to make it easier to read). If you want to do it "correctly" use $(date +%u) -eq 5 instead of $(date +%A) == Friday

Edit: I didn't read the entire question, and missed that you wanted to do it with cron alone. I fear that this is not possible...

Related Question