1

I am trying to schedule a cron, where if a month has 5 weeks and 5 wednesdays, script A.sh should run on 1st week wednesday 2nd week Wednesday, 3rd week wednesday and 4th week wednesday, where as on 5th Week Wednesday it should run b.sh.

Else

I am trying to schedule a cron, where if a month has 4 weeks and 4 wednesdays, script A.sh should run on 1st week wednesday 2nd week Wednesday, 3rd week wednesday, where as on 4th Week Wednesday it should run b.sh.

1 Answers1

2

Original Answer to The Original Question.

You need something like this:

0 1 1-21 * * [ $(date +\%u) -eq 3 ] && "call your command/script here"

This schedule 0 1 1-21 * * means run the jobs "at 01:00AM on every day-of-month from 1 through 21; now the question is why do we limited to 1-21? The answer is because in best case 1day of the month would be already started on Wednesday (so we selected 1) and crontab will be run on 1st, 8th and 15th day-of-month;

And in worst case that would be the last day of first week (day 7), so the crontab would be run on 7th, 14th and 21th day-of-month; and so that's why we limited the running days to 1~21 days of month.

But then man -s 5 crontab says:

Note: The day of a command's execution can be specified by two fields — day of month, and day of week. If both fields are restricted (i.e., don't start with *), the command will be run when e̲i̲t̲h̲e̲r̲ field matches the current time.

and that is why we only choose day-of-month and put * for day-of-week:

crontab-job

instead of specifying day-of-week in crontab as the note pointed above, we are handling that by doing simple test by the shell with [ $(date +\%u) -eq 3 ]; this checks if the day-of-week is the third day of the week, i.e if that is Wednesday; (0-6 of the day-of-week numbers, 0 Mon, ...., 6 Sun) then execute the command/script.


Answer to The Now Revised Question.

0 1 * * 3 [ $(date +\%m) -eq $(date -d'+7days' +\%m) ] && scriptA.sh || scriptB.sh

If it's not the last Wednesday ([ $(date +\%m) -eq $(date -d'+7days' +\%m) ], with this, we are checking that, today's Wednesday's-month $(date +\%m) +7days later (next Wednesday's-month $(date -d'+7days' +\%m)) are in the same month, so it's not the last Wednesday then the scripA.sh will be executed, otherwise it's the last Wednesday and scriptB.sh will be executed.

with above, scriptA.sh will be executed on every Wednesday of the month, except the last Wednesday which then scriptB.sh will be executed.

Of course one could move these tests inside the script[AB].sh instead of complicating things in crontab entries.

Note: Above solution can apply to execute a single commnad/script too by removing the || scriptB.sh part or one could replace it with || true in case you also do not want cron reacts to it by notifying an error via MAILTO for failure cases.

αғsнιη
  • 41,407
  • I think that, when you don't have script B, it's better to add || true instead. Without it, the non-matched week days return false and cron reacts to it by notifying an error via MAILTO. – zakmck Jan 14 '23 at 12:36
  • 1
    @zakmck thanks. I added that – αғsнιη Jan 14 '23 at 13:02