12

Today is Friday, October 3, 2014 3:58 AM

I want to schedule a cronjob like that to run it at the following dates:

  1. Saturday, October 4, 2014 8:00 AM
  2. Saturday, October 18, 2014 8:00 AM
  3. Saturday, November 1, 2014 8:00 AM ... ...

So every 2 weeks , on Saturday, at 8 o'clock.

0

2 Answers 2

30
0 8 * * 6 test $((10#$(date +\%W)\%2)) -eq 1 && yourCommand

date +%W: week number of year with Monday as first day of week, today week 39

10#$(date +%W): conver the date +W to decimal number and avoid shell base parsing confusion

$((39%2)): modulo operation: result is 0 (even week number) or 1 (odd week number), this week result is 1, next week 0

test 1 -eq 1: arithmetic test (equal), in this case result is boolean true

&& yourCommand: Boolean AND: run yourCommand only if result of previous command was boolean true

Note that the year can get two odd weeks: 53 (this year) and 1 (next year)

7
  • 2
    That's elegant! It still, as you've noted, has a corner-case on the 53rd Saturday of the year, which will happen roughly seventy years in every four centuries.
    – MadHatter
    Oct 3, 2014 at 10:11
  • @Cyrus thank you for your answer, but if I write * * * * 5 test $(($(date +%W)%2)) -eq 1 && /u02/restore/scripts/test.sh the script does not run but if I write * * * * 5 /u02/restore/scripts/test.sh script runs. why is your expression not working? I was just testing the cases.And found that not working somehow.
    – kupa
    Oct 3, 2014 at 12:32
  • 1
    My mistake. Cron interprets % as newline. Escape both % with a \ in your cronjob: 0 8 * * 6 test $(($(date +\%W)\%2)) -eq 1 && yourCommand
    – Cyrus
    Oct 3, 2014 at 13:07
  • Sorry to bring back this old question but it wasn't working for me and when i try to execute $((10#$(date +%W)%2)) -eq 1 && echo OK my shell tries to execute the result of the week calculation : -bash: 1: command not found. Any clue why it's doing that ? Thanks.
    – jhuet
    Mar 31, 2017 at 12:35
  • 3
    @jhuet: test is no user it‘s a command. Try: test $((10#$(date +\%W)%2)) -eq 1 && echo odd || echo even
    – Cyrus
    Mar 31, 2017 at 18:23
5

What you've shown is "every week". Then the code is:

0 8 * * 6

Are you sure you need to run it every two weeks?

0 8 * * 6 expr `date +\%s` / 604800 \% 2 >/dev/null || yourCommand
5
  • 1
    Can you explain the command, please
    – kupa
    Oct 3, 2014 at 9:39
  • 1
    It's better to use what Cyrus gave - $(($(date +%W)%2)) "W" stands for a week number the year. Starting from zero to 53. If it can be divided by two, then it's your "every second" week. So cronjob runs every week but the 'expr' executes command yourCommand only if week's number can be divided by 2.
    – Glueon
    Oct 3, 2014 at 9:44
  • when I run test $(($(date +%W)%2)) -eq 1 on command line returns nothing, why?
    – kupa
    Oct 3, 2014 at 9:52
  • 1
    just run echo $? after running that command, to see its return code -- that's what is important with it
    – Ale
    Oct 3, 2014 at 9:55
  • expr says evaluate the following expression. date +%s returns the number of seconds since the Unix Epoch (01/01/1970 00:00:00). 604800 is the number of seconds in 7 days (86,400 sec/day) i.e. number of epoch weeks. %2 is modulo arithmetic, returns 0 if even 1 if odd. || command or && command will determine if the command runs on an odd or even week. This algorithm accuratel handles the 51 or 53 weeks/year problem since it uses Epoch weeks and not Week of the Year.
    – Scottie H
    Aug 24, 2021 at 22:17

You must log in to answer this question.

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