Is it possible to schedule a cron job that would run every three weeks on Wednesday (8AM) only? Or, if that is not possible, to run a job every 27 days or less but on Wednesday at 8AM.


Execute the following script every Wednesday:

[ -f /path/to/timestamp ] && \
  [ `date +%s` -lt $(($(cat /path/to/timestamp)+20*86400)) ] || \
  { date +%s > /path/to/timestamp; your_command; }

where /path/to/timestamp is an arbitrary pathname (which doesn't exist initially), typically somewhere in the user's home directory (in order to avoid symlink attacks, do not use a directory where other users can write to). This script works as follows:

  1. If this pathname doesn't exist yet, then we create it with the current date as its contents and we run the command. The date is represented by the number of seconds since some origin called the epoch.
  2. If this pathname exists (in which case it is assumed that it has been created by this script), then it specifies the date the command was last run. We add 20 days (20*86400 seconds) to this date, and compare the result to the current date. If at least 20 days have passed, we update the pathname contents with the current date and run the command.

Since this script is run every Wednesday (at 8AM) via cron, the command will be run every 3 weeks (as after 1 or 2 weeks, 20 days have not passed yet).

Note that this solution works even if the machine is switched off before the third Wednesday. If for some reason, the machine is switched off the 3rd Wednesday, then the command will be run the next Wednesday the machine is on (the question requires to run the command only on Wednesday at 8AM).

  • It would be interesting to add some explanations. What is the /path/to/timestamp file? What is the content of this file? – A.L Aug 3 '16 at 8:48
  • 1
    @A.L I've just added explanations. – vinc17 Aug 3 '16 at 13:57

If you use GNU/Linux and dillon's crond (look for a package called dcron for your distribution), you can use crontab's finer-grained syntax, as explained in man 1 crontab

0 8 * * wed ID=job1 FREQ=20d your_job

This will execute your_job on wednesday, at 8 am, if at least 20 days have elapsed since last execution.

  • Under Debian/unstable, cron doesn't have these features. – vinc17 Jul 22 '14 at 20:37
  • @vinc17 it must be something specific to dillon's cron then :-( – lgeorget Jul 22 '14 at 20:42
  • we use RedHat Linux and crond is not installed. I want to avoid writing a script. – Ram Jul 22 '14 at 21:50
  • @Ram Is installing dcron an option then? – lgeorget Jul 23 '14 at 6:38

If you already have a cron which is not dcron and don't want to change it, you can use this cron job:

0 8 * * wed  n=0 && [[ -e /home/user/.cronjob && -r /home/user/cronjob ]] && read n < /home/user/.cronjob ; [[ $n == 0 ]] && your_actual_job ; echo $(( (n+1) \% 3 )) > /home/user/.cronjob

This will do a sort of bookkeeping. Every Wednesday, the cron job will be run. It will fetch the value written in .cronjob, which can be 0, 1, or 2. If it's 0, the actual job is run. Then, the value is incremented modulo 3 and written back to .cronjob.

Note the '\' before the '%'. This is needed because cron interprets '%' in a special way.

  • Minor fixes and it will work under sh. – Kusalananda Aug 3 '16 at 14:03
  • A problem with this solution is that if the machine is switched off on the first or second Wednesday after the last run, the next run will occur after 4 weeks instead of 3. – vinc17 Aug 3 '16 at 14:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.