Исполняемый файл Python Script / Unix запускается в терминале, завершается с ошибкой как задание Cron / Launchd

655
JMikes

Я пытаюсь настроить launchd для запуска исполняемого файла сценария / Unix Python (то есть сценарий Python с линией Shebang ). Когда я загружаю файл .plist (ниже), launchctlотображается состояние 127, означающее «Указанная служба не поставлялась с операционной системой». Однако, когда я копирую и вставляю значение, которое я ввел для «программы» в файле .plist в терминал Mac, оно работает нормально.

Я перенаправил stdout / stderr в терминал (через .plist), и он возвращает сообщение,

$ env: python3: нет такого файла или каталога

Если я заменю значение Programв plist на простой пакетный скрипт 'hello world', он будет работать нормально.

Почему программа python (urlwatch) нормально работает в терминале, но возвращает ошибку при вызове через launchd? Как мне это исправить?

Плист файл:

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

В конце концов я хочу запускать скрипт в установленное время дня, но сейчас я использую RunAtLoad= trueдля тестирования, пока не смогу заставить его работать.

Загрузка в launchd и вывод:

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

Позвоните, чтобы проверить статус агента и вывод:

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

Поиск значения кода «127» в терминале:

$ launchctl error 127 127: The specified service did not ship with the operating system 
1
Любая причина, почему вы не используете cron? MMB 6 лет назад 0
Насколько я понимаю, на Mac Cron устарел и заменен на Launchd. https://apple.stackexchange.com/questions/12819/why-is-cron-being-deprecated JMikes 6 лет назад 0
Я попытался запустить ту же программу, используя Cron, и ничего не происходит. В системном журнале я получаю: «cron [7747]: нет пути для адреса 0x109aa6000». Я подозреваю, что это указывает на ту же проблему невозможности найти связанный файл. Мое лучшее предположение (в более общем смысле) заключается в том, что существует проблема, связанная с тем, что переменные среды (например, путь) не одинаковы между запуском в терминале и вызовом через launchd / cron, но я не уверен, как это исправить. JMikes 6 лет назад 0
macOS 10.13 поставляется с python 2.7.10, поэтому по умолчанию нет исполняемого файла python3. Вы добавили это через порты или доморощенный? Если это так, скорее всего, это в / usr / local / bin. Я бы работал над тем, чтобы заставить скрипт работать в терминале как пользователь, от которого вы планируете запускать скрипт launchd. Отладка будет намного проще. MMB 6 лет назад 0
Да, python3 был установлен, и исполняемый файл с таким именем находится в / usr / local / bin. Сценарий Python, который я запускаю (в форме исполняемого файла Unix), прекрасно работает в терминале, что является частью моей путаницы. JMikes 6 лет назад 0
Это предполагает, что что-то отличается в переменных окружения вашей учетной записи пользователя и учетной записи, которую launchd пытается запустить как, потому что он явно не может найти python3. Я не эксперт по launchd, поэтому я не могу объяснить, как launchd получает эти биты. Есть интересное приложение под названием LaunchControl, которое, по-видимому, позволяет вам отлаживать, но я им не пользовался. MMB 6 лет назад 0
Вы правы в том, что это была проблема с переменными среды (она заработала, скоро опубликую ответ). Ранее я попробовал LaunchControl, но не повезло, но спасибо за предложение. Я подозреваю, что LaunchControl не работал, потому что проблема была не в задании (то есть в файле .plist), а в переменных окружения, связанных с выполняемой программой. JMikes 6 лет назад 0
Находя решение проблемы, я понял, что неправильно понял, что делал, и в результате мое описание, вероятно, вводило в заблуждение. Я описал код Python как компилируемый, когда он был фактически не скомпилированным кодом Python, который стал исполняемым с использованием строки Шебанга. Я ошибочно отождествлял себя с возможностью компилирования. С тех пор я обновил вопрос, чтобы исправить эту ошибку, но решить проблему без этой информации было бы практически невозможно. Мои искренние извинения @MMB! Спасибо за вашу помощь точно так же. JMikes 6 лет назад 0

1 ответ на вопрос

1
JMikes

Проблема была с переменными окружения, в частности, что $ PATH отличается для заданий, выполняемых программами cron и vs, которые я вызывал в терминале как вошедший в систему пользователь. Вызов echo $PATHзадания cron и проверка, включает ли он каталог интерпретатора python, может помочь подтвердить, что это проблема.

Два решения:

1) Быстрый и Грязный

Найдите, где установлен интерпретатор Python, и измените строку shebang в верхней части исполняемого файла / сценария unix, чтобы вызвать его напрямую. т.е.

#!/usr/bin/env python3 

становится

#!/usr/local/bin/python3 

Здесь не имеет значения, находится ли интерпретатор Python на пути или нет, потому что его местоположение задано явно. Недостатком является то, что его местоположение теперь жестко запрограммировано, и если вы переместите скрипт на другой компьютер, скрипт может не работать ни в cron, ни при запуске в терминале, если python был установлен в другом месте.

2) Менее быстрый, менее грязный

Напишите сценарий оболочки, который добавляет местоположение интерпретатора Python к пути, если его там еще нет (согласно этому вопросу SuperUser), а затем вызывает сценарий Python. Таким образом, сценарий не был изменен и не будет случайно сломан при перемещении его на компьютер, где python установлен в другом каталоге.

#!/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 

Обязательно сделайте скрипт исполняемым через chmod +x /path/to/script/script.sh

Похожие вопросы