Run a script via cron every other week

15,416

Solution 1

0 0 * * Thu bash -c '(($(date +\%s) / 86400 \% 14))' && your-script

I used bash to do my math because I'm lazy; switch that to whatever you like. I take advantage of January 1, 1970 being a Thursday; for other days of the week you'd have to apply an offset. Cron needs the percent signs escaped.

Quick check:

function check {
  when=$(date --date="$1 $(($RANDOM % 24)):$(($RANDOM % 60))" --utc)
  echo -n "$when: "
  (($(date +%s --date="$when") / 86400 % 14)) && echo run || echo skip
}

for start in "2010-12-02" "2011-12-01"; do
  for x in $(seq 0 12); do
    check "$start + $(($x * 7)) days"
  done
  echo
done

Note I've chosen random times to show this will work if run anytime on Thursday, and chosen dates which cross year boundaries plus include months with both 4 and 5 Thursdays.

Output:

Thu Dec  2 06:19:00 UTC 2010: run
Thu Dec  9 23:04:00 UTC 2010: skip
Thu Dec 16 05:37:00 UTC 2010: run
Thu Dec 23 12:49:00 UTC 2010: skip
Thu Dec 30 03:59:00 UTC 2010: run
Thu Jan  6 11:29:00 UTC 2011: skip
Thu Jan 13 13:23:00 UTC 2011: run
Thu Jan 20 20:33:00 UTC 2011: skip
Thu Jan 27 16:48:00 UTC 2011: run
Thu Feb  3 17:43:00 UTC 2011: skip
Thu Feb 10 05:49:00 UTC 2011: run
Thu Feb 17 08:46:00 UTC 2011: skip
Thu Feb 24 06:50:00 UTC 2011: run

Thu Dec  1 21:40:00 UTC 2011: run
Thu Dec  8 23:24:00 UTC 2011: skip
Thu Dec 15 22:27:00 UTC 2011: run
Thu Dec 22 02:47:00 UTC 2011: skip
Thu Dec 29 12:44:00 UTC 2011: run
Thu Jan  5 17:59:00 UTC 2012: skip
Thu Jan 12 18:31:00 UTC 2012: run
Thu Jan 19 04:51:00 UTC 2012: skip
Thu Jan 26 08:02:00 UTC 2012: run
Thu Feb  2 17:37:00 UTC 2012: skip
Thu Feb  9 14:08:00 UTC 2012: run
Thu Feb 16 18:50:00 UTC 2012: skip
Thu Feb 23 15:52:00 UTC 2012: run

Solution 2

One way might be to use the at utility if you're running Linux. You could put this at the end of your script:

at X + 2 weeks -f myscript

where X is the time you want to run your script at. To initialize just call at for the time you want to run it the first time and then the above statement keeps renewing your scheduled call.

Solution 3

If you can use anacron on the system, things will be much simpler. To use anacron you must have it installed and also you must have root access. It doesn't work on older systems (i.e. RHEL 5.x), the older versions of ancron ONLY run on boot up. It does work with newer systems (i.e. RHEL 6.x).

With anacron, one can schedule jobs in a more flexible way, e.g. run X job once a week. Also anacron runs jobs when computer becomes available, i.e. you don't have to consider when the system is up or down.

To run a script every other week, you have to add a line similar to following to the /etc/anacrontab:

14 5 myScript script.sh

Take a look at the man page for details.

Solution 4

None of the mentioned above tools helped in my case.

See https://techcommunity.microsoft.com/t5/windows-blog-archive/unkillable-processes/ba-p/723389.

Mark Russinovich shows there that there are cases when process can be almost impossible to kill.

Solution 5

Are you on a privileged account? Generally when you receive the "Access Denied" error even on an account with higher access, it is usually because you are trying to kill a service which is critical to the system's operation. Some applications on the other hand, such as VMWare, also implement their own "process protection", even for processes which are not vital to system operation.

If you are on a privileged account, you can give Sysinternals PsKill a shot, I've used it in the past to kill processes that gave me similar error messages. Be careful what processes you're killing though, it may make your system unstable.

Share:
15,416

Related videos on Youtube

dmkmills
Author by

dmkmills

Updated on September 17, 2022

Comments

  • dmkmills
    dmkmills almost 2 years

    I've done quite a bit of research in how to do this, and I see there's no direct way in cron to run a job, say, every other Thursday.

    Right now, I'm leaning toward making a script that will just run every week, and will touch a "flag" file when it runs, and if it runs and the file is already there, to remove the file (and not perform the bi-weekly action).

    My question is, is there any other more elegant or simpler way to accomplish this goal of a bash script of actions running every other week automatically?

    Thanks!

    • Admin
      Admin almost 14 years
      Instead of a flag file, you could use ISO week numbers. (E.g. strftime's %V.)
    • Brian Rasmussen
      Brian Rasmussen almost 14 years
      @Roger: I presume you mean in a conditional within the script.
    • Admin
      Admin almost 14 years
      @Dennis: Doesn't have to be (e.g. see how my answer checks outside the script), but my main point is it would be much simpler and require no state in the filesystem. However, I realized it has a similar drawback as checking day of the month: some years have 53 weeks and some have 52.
  • Jerb
    Jerb almost 14 years
    That would wind up skipping a week if there's a month with 3 Thursdays, though.
  • pferate
    pferate almost 14 years
    Is there a month that has only 3 Thursdays? Although I can see it skip a week if there are 5 Thursdays. It can be updated to 1-7,15-21,29-31, but then it would run back-to-back if there were any matches for the last set...
  • pferate
    pferate almost 14 years
    By 3 Thursdays, did you mean 3 Thursdays that the script would run and not 3 total Thursdays? I may have misread it the first time.
  • JanC
    JanC almost 14 years
    Using anacron is clearly the cleanest solution IMO (unless it has some unwanted consequences for some people).
  • Paul
    Paul over 13 years
    If this is going to be a long term solution i wouldnt recommend running this though at I would create a function in the script which would work out whether it needs to run
  • derobert
    derobert about 12 years
    Seconds since the epoch is inherently in UTC, while cron runs in localtime. If your system timezone isn't UTC, this will lead to confusion. ("Why doesn't it run? Oh, its already Friday in UTC"). The existence of daylight saving time makes working around this much more difficult (though not impossible, since date cal tell you the current UTC offset)