Python Script / Unix Executable wird in Terminal ausgeführt und schlägt als Cron / Launchd-Job fehl

782
JMikes

Ich versuche, launchd so zu konfigurieren, dass ein Python-Skript / eine unix-ausführbare Datei (dh ein Python-Skript mit Shebang-Zeile ) ausgelöst wird . Wenn ich die .plist-Datei (unten) lade, launchctlwird der Status 127 angezeigt und bedeutet: "Der angegebene Dienst wurde nicht mit dem Betriebssystem ausgeliefert". Wenn ich jedoch den Wert, den ich für "Programm" in die .plist-Datei eingegeben habe, in das Mac-Terminal kopiere, wird er einwandfrei ausgeführt.

Ich habe stdout / stderr an das Terminal umgeleitet (über die .plist) und es gibt die Nachricht zurück,

$ env: python3: Keine solche Datei oder Verzeichnis

Wenn ich den Wert von Programin der Plist durch ein einfaches "Hallo Welt" -Equivalenz-Batch-Skript ersetze, funktioniert es gut.

Warum läuft das Python-Programm (urlwatch) im Terminal einwandfrei, gibt aber beim Aufruf über launchd einen Fehler zurück? Wie kann ich das beheben?

Plist-Datei:

<?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> 

Irgendwann möchte ich das Skript zu bestimmten Tageszeiten ausführen, aber jetzt verwende ich RunAtLoad= truezu Testzwecken, bis ich es zum Laufen bringen kann.

Laden in launchd und Ausgabe:

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

Aufruf zum Überprüfen des Status des Agenten und der Ausgabe:

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

Nachschlagen der Bedeutung des Codes '127' im Terminal:

$ launchctl error 127 127: The specified service did not ship with the operating system 
1
Gibt es einen Grund, warum Sie nicht cron verwenden? MMB vor 6 Jahren 0
Wie ich es verstehe, wurde Cron auf Macs nicht mehr empfohlen und durch Launchd ersetzt. https://apple.stackexchange.com/questions/12819/why-is-cron-being-deprecated JMikes vor 6 Jahren 0
Ich habe versucht, dasselbe Programm mit cron auszuführen, und nichts passiert. Im Systemprotokoll erhalte ich: "cron [7747]: kein Pfad für Adresse 0x109aa6000". Ich vermute, dies weist auf das gleiche Problem hin, dass keine verwandte Datei gefunden werden kann. Meine beste Vermutung (allgemeiner) ist, dass es ein Problem mit Umgebungsvariablen (z. B. dem Pfad) gibt, die nicht dasselbe sind, wenn im Terminal ausgeführt wird und über launchd / cron aufgerufen wird, aber ich bin nicht sicher, wie das Problem behoben werden soll. JMikes vor 6 Jahren 0
macOS 10.13 wird mit Python 2.7.10 ausgeliefert, daher gibt es standardmäßig keine ausführbare 'Python3'-Datei. Haben Sie es über Ports oder Homebrew hinzugefügt? Wenn ja, ist es wahrscheinlich in / usr / local / bin. Ich würde daran arbeiten, dass das Skript im Terminal als Benutzer ausgeführt wird, unter dem Sie das launchd-Skript ausführen möchten. Es wird viel einfacher zu debuggen. MMB vor 6 Jahren 0
Ja, python3 wurde installiert und es gibt eine ausführbare Datei mit diesem Namen in / usr / local / bin. Das von mir ausgeführte Python-Skript (in Form einer ausführbaren Unix-Datei) funktioniert gut im Terminal, was Teil meiner Verwirrung ist. JMikes vor 6 Jahren 0
Dies deutet darauf hin, dass die Umgebungsvariablen Ihres Benutzerkontos und das Konto, unter dem launchd ausgeführt wird, anders sind, da Python3 eindeutig nicht gefunden werden kann. Ich bin kein Experte für Launchd und kann daher nicht erklären, wie Launchd diese Teile bekommt. Es gibt eine interessant aussehende App namens LaunchControl, mit der Sie anscheinend debuggen können, aber ich habe sie nicht verwendet. MMB vor 6 Jahren 0
Sie haben Recht, dass es ein Problem mit den Umgebungsvariablen gab (funktionierte, Antwort wird in Kürze veröffentlicht). Ich habe LaunchControl zuvor ohne Erfolg getestet, aber ich danke Ihnen für den Vorschlag. Ich vermute, LaunchControl hat nicht funktioniert, weil das Problem nicht mit dem Job (dh der .plist-Datei), sondern mit den Umgebungsvariablen des laufenden Programms zusammenhängt. JMikes vor 6 Jahren 0
Bei der Suche nach einer Lösung für das Problem wurde mir klar, dass ich missverstanden hatte, was ich tat, und meine Beschreibung war wahrscheinlich irreführend. Ich beschrieb den Python-Code als kompiliert, als er eigentlich nicht kompilierter Python-Code war, der mit einer Shebang-Zeile ausführbar gemacht wurde. Ich hatte mich irrtümlicherweise damit beschäftigt, dass ich mit der Zusammenstellung lauffähig war. Ich habe die Frage seitdem aktualisiert, um diesen Fehler zu korrigieren, aber die Lösung des Problems ohne diese Information wäre praktisch unmöglich gewesen. Meine aufrichtigen Entschuldigungen @MMB! Vielen Dank für Ihre Hilfe. JMikes vor 6 Jahren 0

1 Antwort auf die Frage

1
JMikes

Das Problem lag bei den Umgebungsvariablen, insbesondere, dass sich $ PATH für Jobs unterscheidet, die von cron-vs-Programmen ausgeführt werden, die von mir im Terminal als angemeldeter Benutzer aufgerufen wurden. Der Aufruf echo $PATHin einem Cron - Job und prüfen, ob das Verzeichnis des Python - Interpreter enthält helfen kann, um zu bestätigen, das ist das Problem.

Zwei Lösungen:

1) Schnell und schmutzig

Suchen Sie nach, wo der Python-Interpreter installiert ist, und ändern Sie die Shebang-Zeile oben im unix-Programm für ausführbare Dateien / Python, um sie direkt aufzurufen. dh

#!/usr/bin/env python3 

wird

#!/usr/local/bin/python3 

Dabei spielt es keine Rolle, ob sich der Python-Interpreter im Pfad befindet oder nicht, weil sein Ort explizit angegeben wird. Der Nachteil ist, dass der Speicherort jetzt hartcodiert ist. Wenn Sie das Skript auf einen anderen Computer verschieben, funktioniert das Skript möglicherweise nicht, weder in cron noch im Terminal, wenn Python an einem anderen Speicherort installiert wurde.

2) Weniger schnell, weniger schmutzig

Schreiben Sie ein Shell-Skript, das den Pfad des Python-Interpreters zu dem Pfad hinzufügt, wenn er nicht bereits vorhanden ist (wie in dieser SuperUser-Frage), und dann das Python-Skript aufruft. Auf diese Weise wurde das Skript nicht geändert und nicht versehentlich gebrochen, indem es auf einen Computer verschoben wird, auf dem Python in einem anderen Verzeichnis installiert ist.

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

Stellen Sie sicher, dass das Skript über ausführbar ist chmod +x /path/to/script/script.sh