Scheduling tasks with Mac’s launchd (moving on from cron)

Posted by

With the move to OSX 10.8.2 I have finally given up on cron as a task scheduler. This post is part a record to help me remember, and partly a tutorial for others.

Not that i think there’s anything wrong with cron … how simple is this:

*/2 * * * * /Users/ra/bash/daemonTest.sh

This means run this script every two minutes — you can get a quick intro to cron here .

Anyhow, the clever folks at apple want us to change to launchd.

They have been pushing on this for a while. As a result, every time i have a problem, someone on stackoverflow reminds me that cron’s been deprecated … It’s been going on so long i’m beginning to feel both both old and silly.

Thus, i decided to make a cup of tea and take on the docs.

The first thing i did was to make a script that would just make a log to tell me that the daemon was running. It’s the `daemonTest.sh` script cron called above.

#! /bin/bash

# cd to the logFiles dir
cd /Users/ra/logFiles/

# log date and time to file
echo $(date +"%Y-%b-%d %H:%M:%S") >> daemonLog.txt

Note that i have a ~/logFiles/ folder. If you don’t, this script will fail (make one with mkdir logFiles from $HOME)

Now we have the script, we need to make it executable.

So cd into the containting directory and do the following:

chmod a+x daemonTest.sh

Next, we need to create an xml file which contains our daemon’s instructions.

There are some examples in /Library/LaunchDaemons/ — check them out!

If i were you i’d open one of these in your text editor, and get ready with the cut and paste. Or you can cut and paste mine (below):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-/Apple/DTD PLIST 1.0/EN" "http:/www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.mcj.testDaemon</string>
    <key>ProgramArguments</key>
    <array>
      <string>/Users/mcj/bash/scrapeLaunch.sh</string>
    </array>
    <key>StartInterval</key>
    <integer>120</integer>
  </dict>
</plist>

I saved this as: ~/launchDaemons/com.ra.testDaemon.plist

If you are going to make a few of these, i’d make an ~/launchDaemons/ directory and save it there — that’s what i’ve done.

Finally, we need to install the daemon. You may need super user (sudo) for this step.

cd ~/LaunchDaemons
sudo cp com.ra.testDaemon.plist /Library/LaunchDaemons
launchctl load -w /Library/LaunchDaemons/com.ra.testDaemon.plist

This should now be installed. To check, type the following in bash:

launchctl list

You should be able to see your daemon in the list that’s returned.

If all is going well, you will eventually have a series of timestamps in your logfile.

Let’s check it out (after waiting a bit).

cd ~/logFiles
cat daemonLog.txt

Okay, so assuming you have time stamps two minutes apart, this works. Success!

Now, it’s a pretty stupid script, so let’s get rid of it to stop it from clogging things up:

launchctl unload -w /Library/LaunchDaemons/com.ra.testDaemon.plist
sudo rm /Library/LaunchDaemons/com.ra.testDaemon.plist

If you want to be sure it’s been stopped, wait a while and cat daemonLog.txt again. The most recent time stamp should be around the time you removed the task.

2 comments

  1. Thanks for the handy post! The xml snippet doesn’t refer to the bash script that the rest of the example uses. For clarity, I’d suggest changing the ProgramArguments to /Users/mcj/bash/daemonTest.sh

Comments are closed.