Crontab Timing Tricks

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.

CC BY-SA 4.0 Crontab Timing Tricks by Stephan Sokolow is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

This entry was posted in Geek Stuff. Bookmark the permalink.

1 Response to Crontab Timing Tricks

  1. Joe says:

    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).

Leave a Reply

Your email address will not be published. Required fields are marked *

By submitting a comment here you grant this site a perpetual license to reproduce your words and name/web site in attribution under the same terms as the associated post.

All comments are moderated. If your comment is generic enough to apply to any post, it will be assumed to be spam. Borderline comments will have their URL field erased before being approved.