1

I'm trying to configure launchd to trigger a python script/unix executable (i.e. python script with shebang line). When I load the .plist file (below), launchctl shows a status of 127 meaning, "The specified service did not ship with the operating system". However when I copy and paste the value I've entered for 'program' in the .plist file into the mac terminal it runs fine.

I've redirected stdout/stderr to the terminal (via the .plist) and it returns the message,

$ env: python3: No such file or directory

If I replace the value of Program in the plist to a simple 'hello world' esque batch script it works fine.

Why does the python program (urlwatch) run fine in terminal but return an error when called via launchd? How do I fix it?

Plist file:

<?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>local.careersWatch3</string>
        <key>Program</key>
        <string>/Users/justinmichael/Documents/urlwatch-master/urlwatch</string>
        <key>RunAtLoad</key>
        <true/>
        <key>StandardOutPath</key>
        <string>/dev/ttys000</string>
        <key>StandardErrorPath</key>
        <string>/dev/ttys000</string>
    </dict>
</plist>

I eventually want to run the script at set times of the day, but for now I'm using RunAtLoad = true for testing purposes until I can get it to work.

Loading into launchd and output:

$ launchctl load  ~/Library/LaunchAgents/local.careerswatch3.plist
$ env: python3: No such file or directory

Call to check status of agent and output:

$ launchctl list | grep local.careersWatch3
-   127 local.careersWatch3

Looking up the meaning of code '127' in terminal:

$ launchctl error 127
127: The specified service did not ship with the operating system
8
  • Any reason why you aren't using cron?
    – MMB
    Feb 12, 2018 at 7:38
  • As I understand it, on Macs, Cron has been deprecated and replaced with Launchd. apple.stackexchange.com/questions/12819/…
    – JMikes
    Feb 12, 2018 at 15:26
  • I've tried running the same program using cron and nothing happens. In the system log I get: "cron[7747]: no path for address 0x109aa6000". I suspect this indicates the same problem of being unable to find a related file. My best guess (more generally) is that there's a problem with environment variables (e.g. the path) not being the same between running in terminal and calling via launchd/cron but I'm not sure how to fix it.
    – JMikes
    Feb 12, 2018 at 16:25
  • macOS 10.13 ships with python 2.7.10, so there is no 'python3' executable, by default. Did you add it via ports or homebrew? If so, it's likely in /usr/local/bin. I'd work on getting the script to work in the terminal as the user you plan to run the launchd script as. It will be much easier to debug.
    – MMB
    Feb 14, 2018 at 7:51
  • Yes, python3 has been installed and there is an executable by that name in /usr/local/bin. The python script that I'm running (in the form of a unix executable) works fine in the terminal which is part of my confusion.
    – JMikes
    Feb 17, 2018 at 2:30

1 Answer 1

1

The problem was with the environment variables, specifically that the $PATH is different for jobs run by cron vs programs called by me in terminal as a logged in user. Calling echo $PATH in a cron job and checking if it includes the directory of the python interpreter can help to confirm this is the problem.

Two solutions:

1) Quick and Dirty

Find where the Python interpreter is installed and change the shebang line at the top of the unix executable/python script to call it directly. i.e

#!/usr/bin/env python3

becomes

#!/usr/local/bin/python3

Here, it doesn't matter if the python interpreter is on the path or not because it's location is given explicitly. The downside is that its location is now hard-coded and if you move the script to a different computer the script may not work, neither in cron nor when run in the terminal, if python has been installed in a different location.

2) Less Quick, Less Dirty

Write a shell script that adds the location of the python interpreter to the path if it isn't already there (as per this SuperUser question) and then calls the python script. This way the script hasn't been changed and won't be accidentally broken by moving it to a computer where python is installed in a different directory.

#!/bin/bash
# directory python is found in
dir="usr/local/bin"
#add to path if not there
if [ -d "$dir" ] && [[ ":$PATH:" != *":$dir:"* ]]; then
        PATH="${PATH:+"$PATH:"}$dir"
fi
#Run program
/path/to/program/program_name

Be sure to make the script executable via chmod +x /path/to/script/script.sh

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .