Advertisement

Terminally Geeky: Deadline reminders using Growl, sleepwatcher, and GNU date

When I have a large deadline looming, I like to keep track of how many days I have left.

I've tried Dashboard widgets, iPad apps and just about anything else you could think of, but they all have failed for one simple reason: they require me to check them. I can go days or weeks without triggering the Dashboard, and an iOS countdown app still requires that you check it. I could use something like Due app, but I really don't want something actively distracting me -- I want something passively reminding me. Nor do I want these cluttering up my iCal.

I found my solution by cobbling together several bits of free Unix utilities that are essential to any true geek's tool belt.

Preparation

First, make sure you have the GNU Coreutils installed. You could install them manually, but if you don't have them already, I suggest getting them either from MacPorts (sudo port install coreutils) or Rudix (if you're not familiar with Rudix, check out our previous coverage). We're going to be using the GNU version of 'date', which MacPorts puts in /opt/local/bin/gdate and Rudix installs to /usr/local/bin/date. Set the GNUDATE variable to the appropriate path below.

Second, you'll need SleepWatcher, which is another free program that will automatically run shell scripts whenever your computer goes to sleep or wakes up. Download the file and follow the instructions in the ReadMe.rtf to install it. (Note that you may need to create /usr/local/sbin/ before installing it: 'sudo mkdir /usr/local/sbin').

Third, you'll need 'growlnotify' from Growl. Download the regular Growl DMG, mount it and install the growlnotify.pkg from inside the 'Extras' folder.

OK, now all of that sounds complicated, but it shouldn't take you more than a few minutes, and once you install all the necessary pieces, you'll be ready to do other cool things with them in the future.

The Script

Now that we have all of the necessary pieces, we just need to put them to good use. Once you have SleepWatcher installed and working (don't forget about installing the launchd plist and loading it as instructed in the ReadMe.rtf), your personal 'wakeup' script will be kept at ~/.wakeup, and you'll need to add the following lines to it (the #!/bin/sh line should be the very first line of the file, and should only appear once).

#!/bin/sh

### Deadline Reminder
## if you installed coreutils using the Rudix installer, uncomment the next line
# GNUDATE=/usr/local/bin/date

## if you installed coreutils using MacPorts, uncomment the next line
# GNUDATE=/opt/local/bin/gdate

# March 1st is my deadline. Change '1 march' to your deadline!
DUEDATE=`$GNUDATE '+%j' --date '1 march'`

# today's date
TODAYDATE=`$GNUDATE '+%j'`

DAYSLEFT=`expr $DUEDATE - $TODAYDATE`

growlnotify -a "Scrivener" --sticky --message "$DAYSLEFT days left" "Thesis"

What it does

What the script does is very simple. Using GNU date, it calculates the day of the year (0-365 or 366 in a leap year) of your deadline. For example, March 1 is the 60th day of the year 2011 (31 days in January + 28 days in February), so if I did

gdate '+%j' --date '1 march 2011'

I would get

060

So, in the above script "$DUEDATE" gets set to 060 and then compared to "$TODAYDATE", which gets set to whatever day today is (for example, Feb 18 is 049). Then we use 'expr' to subtract $TODAYDATE (049) from $DUEDATE (060) and get 11 days remaining, which is put into the variable $DAYSLEFT.

Once the information is calculated, we have to display it to the user. That's where growlnotify comes in. I am writing my Thesis in Scrivener so I tell growlnotify: "Using Scrivener's app icon, show me an alert window telling me I have $DAYSLEFT days left. Make the title of the window "Thesis" and make the window 'sticky' meaning that it will not go away until I click on it.

You could leave --sticky off if you wanted the alert to go away automatically, but I want to have to acknowledge it.

Known Bugs/Limitations

Note that this script assumes that your deadline is in the current calendar year. If I tried to run this script on December 15, 2010 and my deadline wasn't until March 1, 2011, I would get -289 because the script doesn't take 'year' into consideration; it would be counting the days between March 1 (the 60th day of the year) and December 15 (the 349th day of the year).

Solving that problem will be, as Dr. Cupper (my Computer Science professor) used to say, "Left as an exercise for the reader."