2007-03-04

Crontab Timing Tricks

Posted in Geek Stuff at 17:02

Have you ever had a cronjob that needs to run as root, but you can’t do so easily because of the following reasons?

  • /etc/crontab is managed by your package manager
  • vixie-cron ignores /etc/cron.d/
  • Root’s private “crontab -e” crontab is easily overlooked when backing up /etc
  • It needs some odd interval like “every 3 days”

Well, if your interval is evenly divisible into days, (”every 2 days” is OK, “every 1.5 days” is not) then I have just the solution. Create a new cron script in /etc/cron.daily, make it executable, and put the following inside it (For our example, I’ll use two days as the interval and “emerge –sync” as the command):

#!/bin/bash

TODAY=`date +%j`
if [ $((${TODAY#0} % 2)) == 0 ]; then
        /usr/bin/emerge --sync > /dev/null
fi

It’s that simple. Here’s how it works:

  1. Once per day, the cron daemon calls the script
  2. The script calls `date +%j` and gets the “day of the year” (between 1 and 365, inclusive, or 1 and 366 if it’s a leap year)
  3. It then strips off any leading zeros to prevent “invalid number for given base” errors. (”085″ would be “invalid octal” by bash syntax.)
  4. The script does a “modulo 2″ operation on it (takes the remainder of integer division by 2)
  5. If there is no remainder, then the current date satisfies the “every second day” requirement and the command is run.

Because I chose the evenly-numbered days using “== 0″, a non-leap year will end with a two-day interval, rather than a leap year ending with the command being called two days in a row. Use “!= 0″ if you want to change this behaviour.

The “> /dev/null” ensures that only stderr messages (usually only errors) generate status emails. I use that to keep my admin mailbox uncluttered.

UPDATE: Oops. I forgot that bash is one of the many languages which uses a zero prefix to indicate octal. I’ve corrected the example.

Creative Commons License
The Crontab Timing Tricks by Stephan Sokolow, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Share Alike 2.5 Canada License.

1 Comment »

  1. Joe said,

    2007-06-01 at 11:44

    Stephan,

    Thanks for the tip! I also had a strange interval — every 29 days. I ended up using a slightly different technique to get the number of days:

    let upSeconds=`cat /proc/uptime | cut -f1 -d.`
    let days=$((${upSeconds}/86400))

    After that, my solution was about the same as yours (i.e. check if days % 29 equals 0).

RSS feed for comments on this post · TrackBack URL

Leave a Comment

By submitting a comment here you grant this site a perpetual license to reproduce your words and name/web site in attribution.

Bad Behavior has blocked 55 access attempts in the last 7 days.