2

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?

3
  • I don't have a better solution using cron (my choice would be your suggestion to run on 18th, 19th, and 20th, and check the date in the script). An alternative to cron, systemd.timer allows you to specify multiple OnCalendar= events, which trigger when any of them matches. You can specify one event for Mondays to Fridays on the 20th: OnCalendar='Mon-Fri *-*-20 00:00:00', and another one for Fridays on the 18th and 19th: OnCalendar='Fri *-*-18-19 00:00:00'. Jul 17, 2020 at 7:56
  • *-*-18-19 should be *-*-18..19. Jul 17, 2020 at 9:46
  • Thank you for the suggestion @JohanMyréen! I didn't know systemd.timer. I'll have a look and check what's more feasible for me. Jul 17, 2020 at 13:08

2 Answers 2

2

You could run it on the 18,19,20 and check the current date like:

0 6 18,19,20 * * case $(LC_ALL=C date +\%a\%d) in (Sat*|Sun*);; (Fri18|Fri19|*20) /opt/example.sh; esac

Which allows the 20th as long as it's neither Saturday nor Sunday, or the 18th or 19th as long they fall on a Friday.

1
-3

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...

5
  • I believe this should work, if I incorporate the if statement in the command that is executed in the crontab :) Jul 17, 2020 at 10:57
  • I think I'll add the check date check in the /opt/example.sh script, and simply have a cronjob run it on 18th, 19th and 20th. the script will run on each day, but simply exit if it's a Saturday or Sunday. Jul 17, 2020 at 13:10
  • That's not correct sh/[ syntax. Mar 15, 2021 at 7:13
  • 1
    Also running date several time to get several components of the same date is wrong as the date could change between invocations. Mar 15, 2021 at 7:13
  • 1
    That still runs it ever 20th of the month. Mar 15, 2021 at 7:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .