Pro Terminal: Automate the Boring Stuff with launchd


We spend a lot of time doing tedious things with computers. Magical though they may be, and as powerful as they are, folks still use computers to manually enable repetitive tasks. With just a teaspoon of programming knowledge, you can automate the boring parts of your computing life. launchd is one of those tools that can help you out. It’s a command-line tool for starting, stopping and managing scripts and processes. Linux users or system admins will recognize launchd as cron in macOS.

What are daemons?

launchd

Daemons (pronounced “demons”) are processes that run in the background of your computer. If you’re interested in a little etymology, the unusual name comes from Maxwell’s demon, an imaginary agent that sorts molecules in a thermodynamics thought experiment. Their process names typically end in “d,” and you’ll find them everywhere. Take a look at Activity Monitor and you’ll see plenty daemons spawned by macOS itself, with names like trustd, fseventsd, powerd and even lsd. Unlike applications, daemons run as processes, and are not under the direct control of the user or another application. On macOS, system and user daemons alike are under the control of the launchd framework, which decides when they start and stop.

Writing scripts

In order to run daemons through launchd, you’ll need to write some scripts. Scripts represent the tasks that the computer will run, and you’ll need to do a little programming. The most common scripting language is bash, but you can also use Python. It’s a fairly straightforward scripting language that you can pick up from some excellent online tutorials. Here’s a (very Web 1.0) bash scripting how-to and a Lifehacker post on bash scripts that are a good starting point.

Using launchd

launchd job description

Scripts in launchd are trigged by job definitions. These are preference list (.plist) files stored in specific directories. These XML files give the job a name, specify the script that should be launched and indicate when the script should fire. Once you’ve written your script, you’ll write and load a job definition that launches the script at the appropriate time.

A job definition looks something like what’s below:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>local.restart</string>
        <key>Program</key>
        <string>/Users/user/Scripts/restart.sh</string>
        <key>RunAtLoad</key>
        <true/>
    </dict>

Tweak this files as needed with the parameters below. Then save the file with a .plist extension in the correct directory (see below).

There are a few key parts to the job description:

  • Label: the name of the job within launchd. Must be unique for each job. These are traditionally written in reverse domain notation, (com.apple.screensaver, for example). “local” is a great domain for private agents.
  • Program: the fully-qualified path to the script launched by this job description
  • RunAtLoad: describes when the script should be run. There are a few different options here:
    • RunAtLoad: run as soon as the job definition is loaded. Runs only once per load unless otherwise scheduled. False if unspecified.
    • StartInterval: start the job every n seconds. The example below will run the job every 7200 seconds, or every 2 hours. Time must be specified in seconds.
      <key>StartInterval</key> 
      <integer>7200</integer>
    • StartCalendarInterval: run the job at a specific time and date. The below will run the job every day at 9 AM.
      <key>StartCalendarInterval</key> 
      <dict> 
          <key>Hour</key> 
          <integer>9</integer> 
          <key>Minute</key> 
          <integer>0</integer> 
      </dict>

Agents vs. daemons

Once you’ve written your job description, you’ll need to save it in the appropriate directory.

launchd further distinguishes between agents and daemons. An agent runs on behalf of the logged in user, while a daemon runs under the root user. This means that, if you want to restrict a script to a specific user account, you can use an agent. If you want something to run no matter who is logged in, you’ll use a daemon.

The difference between agents and daemons is drawn from where they’re saved on the computer:

  • ~/Library/LaunchAgents runs on behalf of the logged in user
  • /Library/LaunchDaemons runs on behalf of the root users.

You’ll need to save your plist in the correct location in order to make the script run properly. If you’re not sure where to save it, ~/Library/LaunchAgents is probably a good choice.

Loading jobs into launchctl

launchd launchctl list

Once you’ve created you scripts and saved your job description into the right place, you’ll need to load it into launchctl. Provided you saved your job description in one of the previously mentioned directories, this will happen automatically on future logins.

To see what’s current running in laucnhctl, you can use launchctl list. This giant list can be grepped for your script by label with something like the following:

launchctl list | grep local.restart

To load a script, open up Terminal and use the following command. Replace the directory path with the path to your script. Note that the job description’s filename and the job name are almost identical, which is good practice for organizing your scripts.

launchctl load ~/Library/LaunchAgents/local.restart.plist

launchd launchctl load

To remove the script from the launchctl queue, use the unload command:

launchctl unload ~/Library/LaunchAgents/local.restart.plist

launchd launchctl unload

Loading a job puts it into the launchd queue, and the job will run at the time specified in its launch conditions. If you want to run an script immediately no matter what, you should use the “start” command:

launchctl start local.restart

This command takes the job’s label, and will only work if the job has already been loaded into launchctl.

Conclusion

You can use launchd to create scripts that do things like clean up files, restart your server on a schedule or run an application when a certain file is appears. To learn a lot more about launchd, you can check out the laucnhd tutorial, from which much of the this information is drawn.

Image by User:Htkym (Own work) [GFDL, CC-BY-SA-3.0 or CC BY 2.5], via Wikimedia Commons

You might also be interested in the following:

Getting Started with Terminal: Using Grep to Search Files

How to Use macOS’ Activity Monitor Like a Power User

How To: Monitor CPU Usage From Your Dock


Kokou Adzo

Kokou Adzo is a stalwart in the tech journalism community, has been chronicling the ever-evolving world of Apple products and innovations for over a decade. As a Senior Author at Apple Gazette, Kokou combines a deep passion for technology with an innate ability to translate complex tech jargon into relatable insights for everyday users.

0 Comments

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