So recently I made a Go app that removes the screenshots from the Desktop. It can be found here Screenshot Remover.
I created this app because I often take a lot of screenshots, which quickly clutter up my Desktop. To keep things tidy, the script automatically removes any image on the Desktop that hasn’t been modified in the last 7 days. That gives me plenty of time to save any screenshots I actually need, while keeping the rest from piling up.
Now the next question, how do I save run the executable daily at some specific time?
The obvious solution is cron
as that is something known and used by everyone. But while researching, I found that Apple recommends using launchd
for timed jobs over cron
in OS X.
So here are the steps to run an executable automatically daily at a specific time -
Creating a LaunchAgent (.plist) file
So what is LaunchAgent and what is a plist file?
In Mac OS, launchd
is the primary system which is used to manage system services and any processes.
A LaunchAgent is a type of job which is managed by launchd
. In simple terms, a LaunchAgent is a process that is run on behalf of the user when that user is logged in.
A .plist
file stands for Property List. It is a file format that is used by MacOS for storing structured data.
In our context, a .plist file is the config file that contains information about everything launchd
needs to know to manage the job.
With the above details clear, please create a .plist file with the name of com.user.myjob.plist
inside the ~/Library/LaunchAgents/ with any name.
Editing the .plist File
Now the next question, how do we use a plist file to trigger an executable?
Turns out, we can write xml code inside a plist file. So let's do that. Paste the following code inside the file -
<?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.user.myjob</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/your/executable</string>
</array>
<!-- Run every day at 7:30 AM -->
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>7</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
<key>StandardOutPath</key>
<string>/tmp/myjob.out</string>
<key>StandardErrorPath</key>
<string>/tmp/myjob.err</string>
</dict>
</plist>
So what does this code do? Lets walk through the important stuff line by line. First we have this -
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
The above code specifies the DTD for a property list and tells macOS to interpret this XML as a plist file.
<dict>
This opens a dictionary. In plist files, this is a key-value map similar to JSON objects.
<key>Label</key>
<string>com.user.myjob</string>
Label is basically a unique identifier for this job. Kinda like the job's internal id.
<key>ProgramArguments</key>
<array>
<string>/path/to/your/executable</string>
</array>
Program Arguments defines what program needs to be executed. An array is used here because sometimes someone needs to provides multiple arguments. In our case, we only need to provide the full path of where the executable is stored.
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>7</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
This defines when the job should run. In our case, it is set to run at 7:30 AM daily. This dict allows us to specify multiple fields like Hour, Minute, Weekday, Month etc.
<key>StandardOutPath</key>
<string>/tmp/myjob.out</string>
<key>StandardErrorPath</key>
<string>/tmp/myjob.err</string>
How can we verify if this is running as expected or encountering errors? We can do that using keys to redirect the program's output.
The StandardOutPath
is used for normal output (stdout
) and the StandardErrPath
is used for the error messages (stderr
).
So once the job is run, we can check out /tmp/myjob.out
and /tmp/myjob.err
to debug.
So now we have the plist ready to run the job. But we still need one more step.
Load the job with launchctl
So we have the plist file, but we still need to inform launchd
to load it. Thankfully it can be done with just one command.
launchctl load ~/Library/LaunchAgents/com.user.myjob.plist
And after this you can use the following command to verify that it has loaded.
launchctl list | grep com.user.myjob
And that’s it! Your job is scheduled successfully. We have configured a plist file to run an executable daily or whenever we want.
Top comments (0)