11

Is there a way to schedule a cron job to run every fortnight?

(One way I can think of, within crontab, would be to add two entries for "date-of-month"...)

4

3 Answers 3

14

No, cron only knows about the day of the week, the day of the month and the month.

Running a command twice a month on fixed days (e.g. the 1st and the 16th) is easy:

42 4 1,16 * *  do_stuff

Running a command every other week is another matter. The best you can do is to run a command every week, and make it do nothing every other week. On Linux, you can divide the number of seconds since the epoch (date +%s) by the number of seconds in a week to get a number that flips parity every week. Note that in a crontab, % needs to be escaped (cron turns % into newlines before executing the command).

42 4 * * 1  case $(($(date +\%s) / (60*60*24*7))) in *[02468]) do_stuff;; esac
1
  • 2
    According to the documentation I have at hand, cron turns percent signs into newlines and pipes everything that was after the first percent sign into the command. Not that it matters much, I guess; I don't think I've ever willingly used this feature.
    – dhag
    Apr 20, 2015 at 0:02
2

You cannot directly have cron run a job fortnightly (every two weeks). However, it is reasonably straightforward to ensure that the main part of the job runs only every other week. @Gilles has offered one solution; here's another:

42 4 * * 1    test 1 -eq $(($(date +\%g) & 1)) && do_stuff...

The date +%g command returns the current week number (of the year), and this is bitwise ANDed to return either 1 or 0 before being used to determine whether the real job can be run.

The same caveat on the percent symbol %: in a crontab entry it must be escaped to prevent cron treating it specially.

1
  • 2
    My one concern with this week-number-based solution is that a year consists of 52 weeks plus an extra day (two days in the case of leap years). I think this would lead to a situation where, occasionally, there will be Monday 31st December in week 53 followed by Monday 7th January in week 1. Both week numbers are odd, so the job would run in consecutive weeks.
    – user140906
    Oct 30, 2015 at 10:37
2

I know I'm late to the party but, everyone wants a solution or three to any problem...

I found this post while wanting to do the same thing as the OP, except for a Sunday.

@user140906 has a valid concern, which can be observed when running this snippet;

for n in $(seq 17 33); do ncal -A1 -bw dec 20${n}; done

Which initially seems to repeat every 6 years - I didn't check them all! :-)

I then found this link which offers two solutions, one similar to @gilles-so-stop-being-evil, that should work, the most obvious one is below;

#!/bin/bash

# a file marking the state on disk
mark_file=$HOME/.job-run-marker-1

# check whether the job run last time it is invoked
if [ -e $mark_file ] ; then
  rm -f $mark_file
else
  touch $mark_file
  exit 0
fi

# job command is here

Coupled with a crontab entry like;

0 2 * * 2 my_script

Easily adapted to be used for multiple crontab entries (pass a value for mark_file or an ID instead of hard-coding it), or expand the same logic with some grep / awk / sed magic, to add/remove/append lines in a file that represent the ID and status/date of each job execution.

Either way, hopefully that helps someone, perhaps even a future me!

You must log in to answer this question.

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