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”…)
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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
Method 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.
Method 3
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!
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0