Automate Any Task on Mac Using LaunchAgents

Rohit Saini
5 min read6 days ago
Photo by Gabriel Heinzer on Unsplash

Introduction

Automation can significantly enhance productivity by eliminating repetitive tasks. On macOS, LaunchAgents provides a powerful mechanism to automate tasks, such as running scripts or applications at scheduled intervals. This guide will walk you through the process of using LaunchAgents to automate a Python script, but the principles can be applied to any executable task.

What are LaunchAgents?

LaunchAgents are part of the launchd system, a unified, open-source service management framework for starting, stopping, and managing daemons, applications, processes, and scripts. While LaunchDaemons are generally used for system-wide services, LaunchAgents are intended for per-user services and applications.

Prerequisites

Before we dive into the setup, ensure you have the following:

  • A Mac running macOS.
  • A task or script you want to automate. For this guide, we’ll use a Python script as an example.
  • Basic familiarity with Terminal commands.

Step-by-Step Guide

Step 1: Write Your Script

For demonstration purposes, let’s create a simple Python script located at /Users/yourusername/Documents/your_script.py.

# /Users/yourusername/Documents/your_script.py

print("Hello, World! This script runs automatically.")

Step 2: Create a Shell Script (Optional but Recommended)

To ensure your script runs with the appropriate environment and permissions, wrap it in a shell script. Create run_script.sh in the same directory.

#!/bin/bash

# Path to Python script
PYTHON_SCRIPT="/Users/yourusername/Documents/your_script.py"

# Ensure the script is executable
chmod +x "$PYTHON_SCRIPT"

# Run the Python script
/usr/bin/python3 "$PYTHON_SCRIPT"

Make the shell script executable:

chmod +x /Users/yourusername/Documents/run_script.sh

Step 3: Create the plist File

Create a plist file that will instruct launchd how and when to run your task. Save this file as com.user.script.plist.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.script</string>

<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/yourusername/Documents/run_script.sh</string>
</array>

<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>14</integer>
<key>Minute</key>
<integer>30</integer>
</dict>

<key>StandardOutPath</key>
<string>/Users/yourusername/Documents/script.log</string>
<key>StandardErrorPath</key>
<string>/Users/yourusername/Documents/script.error.log</string>

<key>RunAtLoad</key>
<true/>
</dict>
</plist>

let’s break down this snippet line by line to better understanding:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  • <?xml version="1.0" encoding="UTF-8"?>: This line declares the file as an XML document and specifies the version of XML and the character encoding used (UTF-8).
  • <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">: This line specifies the Document Type Definition (DTD) for the plist, which describes the structure and legal elements and attributes.
  • <plist version="1.0">: This line declares the start of the plist document and specifies its version.
  • <dict>: This tag starts a dictionary, which is a collection of key-value pairs. In a plist, a dictionary is used to define the properties of the configuration.
    <key>Label</key>
<string>com.user.script</string>
  • <key>Label</key>: This defines a key named Label. In LaunchAgents, the Label key uniquely identifies the job.
  • <string>com.user.script</string>: This provides the value for the Label key. The label is a unique identifier for the LaunchAgent, typically in reverse domain notation.
    <key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/yourusername/Documents/run_script.sh</string>
</array>
  • <key>ProgramArguments</key>: This defines a key named ProgramArguments. It specifies the command and arguments to execute.
  • <array>: This tag starts an array, which is a list of values.
  • <string>/bin/bash</string>: This specifies the command to run, which in this case is bash, the Unix shell.
  • <string>/Users/yourusername/Documents/run_script.sh</string>: This specifies the argument to the bashcommand, which is the path to the shell script that runs the Python script.
    <key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>14</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
  • <key>StartCalendarInterval</key>: This key specifies the schedule on which the job should run.
  • <dict>: This tag starts another dictionary, which contains the scheduling information.
  • <key>Hour</key><integer>14</integer>: These lines specify the hour of the day the job should run (14, which is 2 PM).
  • <key>Minute</key><integer>30</integer>: These lines specify the minute of the hour the job should run (30).
    <key>StandardOutPath</key>
<string>/Users/yourusername/Documents/script.log</string>
<key>StandardErrorPath</key>
<string>/Users/yourusername/Documents/script.error.log</string>
  • <key>StandardOutPath</key>: This key specifies the file path where the standard output (stdout) of the script will be written.
  • <string>/Users/yourusername/Documents/script.log</string>: This provides the path to the log file for standard output.
  • <key>StandardErrorPath</key>: This key specifies the file path where the standard error (stderr) of the script will be written.
  • <string>/Users/yourusername/Documents/script.error.log</string>: This provides the path to the log file for standard error.
    <key>RunAtLoad</key>
<true/>
</dict>
</plist>
  • <key>RunAtLoad</key>: This key indicates that the job should run immediately when the LaunchAgent is loaded.
  • <true/>: This sets the value of RunAtLoad to true, meaning the script will execute as soon as the plist is loaded by launchctl.
  • </dict>: This closes the dictionary that began at the start of the plist.
  • </plist>: This closes the plist document.

Summary

This plist file configures a LaunchAgent to:

  • Run a shell script located at /Users/yourusername/Documents/run_script.sh using bash.
  • Schedule the task to run daily at 2:30 PM.
  • Log the standard output and error to specified log files.
  • Run the task immediately when the plist is loaded.

This setup ensures your script is executed automatically and you have logs for troubleshooting if anything goes wrong.

Step 4: Move the plist File to the LaunchAgents Directory

For user-level agents, the plist file should be placed in ~/Library/LaunchAgents/. If this directory does not exist, create it:

mkdir -p ~/Library/LaunchAgents/
cp com.user.script.plist ~/Library/LaunchAgents/

Step 5: Load the plist File

Use the launchctl command to load the plist file and start the agent:

launchctl load ~/Library/LaunchAgents/com.user.script.plist

To unload it, you can use:

launchctl unload ~/Library/LaunchAgents/com.user.script.plist

Step 6: Verify the Automation

Check the log files specified in the plist (script.log and script.error.log) to verify that your script runs as expected.

Advanced Configuration

LaunchAgents offers several options for fine-tuning your automation:

  • StartInterval: Specify the interval in seconds between invocations.
  • KeepAlive: Ensure the script is always running.
  • EnvironmentVariables: Set environment variables for your script.

Refer to the official Apple documentation for a comprehensive list of keys and options.

Troubleshooting

If your script isn’t running as expected, consider these steps:

  • Ensure the plist file syntax is correct.
  • Check file permissions and paths.
  • Examine system logs for errors (Console.app or log show --predicate 'process == "launchd"').

Conclusion

Using LaunchAgents on macOS provides a robust way to automate tasks, making it easier to manage repetitive jobs and ensure they run at specified times. Whether you're a developer, system administrator, or a casual user, mastering LaunchAgents can significantly enhance your workflow efficiency.

By following this guide, you should be able to set up and manage automated tasks seamlessly on your Mac. Happy automating!

--

--

Rohit Saini

कर्म मुझे बांधता नहीं, क्योंकि मुझे कर्म के प्रतिफल की कोई इच्छा नहीं |