Launchctl минимальный рабочий пример с Python

Я хотел бы запускать скрипт на Python каждую минуту, используя launchd. Мой файл plist выглядит так:

<?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.turtle.script.plist</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/python</string>
        <string>/Users/turtle/Desktop/turtle.py</string>
        <string>/Users/turtle/Desktop/data/data.txt</string>
    </array>
    <key>StartInterval</key>
    <integer>60</integer>
</dict>
</plist>

Этот файл plist выглядит хорошо, так как я получаю следующее:

plutil -lint com.turtle.script.plist
com.turtle.script.plist: OK

Скрипт работает, когда я запускаю его из командной строки:

/usr/bin/python /Users/turtle/Desktop/turtle.py /Users/turtle/Desktop/data/data.txt

Я загружаю этот список через:

   launchctl load -w -F com.turtle.script.plist

Я также попробовал:

sudo launchctl load -w -F com.turtle.script.plist

Я загружаю эту работу, и скрипт python должен записать файл на диск. Однако файл не создается. Я рассматриваю работу с:

sudo launchctl list | grep com.turtle.script.plist

Выход:

- 1 com.turtle.script.plist

Может ли кто-нибудь помочь решить проблему?

3 ответа

Решение

Похоже, что внутри скрипта есть некоторая зависимость от среды - по сути, она предполагает что-то относительно среды, в которой он работает, это правильно, когда вы запускаете его вручную, а не когда запускает launchd. Не зная ничего о сценарии, трудно указать, что это может быть, но я могу предложить несколько вещей, на которые стоит обратить внимание:

  • sudo launchctl не более мощная версия launchctl, это делает что-то значительно другое. Вы должны выяснить, какой вы хотите, и использовать его.

    Когда ты бежишь launchctl как обычный пользователь (например, launchctl load), он взаимодействует с вашим пользовательским экземпляром launchd, чтобы управлять агентами запуска - элементами, которые запускаются в вашем пользовательском сеансе под вашим именем пользователя.

    Когда ты бежишь launchctl как корень (например, sudo launchctl load), он взаимодействует с системным экземпляром launchd для управления демонами запуска - элементами, которые выполняются в системном контексте как root.

    Вам нужно будет решить, какой из них подходит, основываясь на том, что делает этот скрипт.

  • Проверьте system.log (вы можете использовать консольную утилиту, чтобы просмотреть его, или tail -f /var/log/system.log) и посмотрите, есть ли в нем что-либо, указывающее, почему скрипт не работает.

  • Добавьте записи в файл launchd.plist, чтобы записать вывод сценария и посмотреть, содержит ли он какие-либо сообщения об ошибках или другие признаки того, что происходит не так:

    <key>StandardOutPath</key>
    <string>/tmp/turtle.out</string>
    <key>StandardErrorPath</key>
    <string>/tmp/turtle.err</string>
    

    Это может помочь отредактировать скрипт для добавления отладочной информации, чтобы вы могли больше рассказать о том, как он работает (/ не работает).

  • Зависит ли сценарий от наличия определенного рабочего каталога и / или переменных среды? Если это так, добавьте соответствующие WorkingDirectory и / или EnvironmentVariables элементы в.plist.

Ваш файл.plist в ~/Library/LaunchAgents:

<?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>local.tf.check_up</string>
    <key>Program</key>
    <string>/Users/tf/.bin/check_up.py</string>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardErrorPath</key>
    <string>/tmp/local.tf.check_up.stderr</string>
    <key>StandardOutPath</key>
    <string>/tmp/local.tf.check_up.stdout</string>
    <key>StartInterval</key>
    <integer>60</integer>
    <key>WorkingDirectory</key>
    <string>/tmp/</string>
</dict>
</plist>

Ваш сценарий /Users/tf/.bin/check_up.py:

#!/opt/local/bin/python

f = open('/Users/tf/Desktop/test.txt', 'a')
f.write('hello again 4\n')
f.close()

Обратите внимание, что я использую python от MacPorts, который живет в /opt/local/bin/, Если вы используете другой интерпретатор Python, замените приведенную выше строку $ which python возвращается.

Убедитесь, что ваш скрипт исполняемый и только у вас есть права на запись:

$ chmod 755 ~/.bin/check_up.py

Чтобы проверить скрипт: Запустите его и убедитесь, что он работает как следует:

$ ~/.bin/check_up.py

Загрузите LaunchAgent:

$ launchctl load ~/Library/LaunchAgents/local.tf.check_up.plist

Попробуй написать /tmp который может быть написан любым пользователем. т.е. изменить /Users/turtle/Desktop/data/data.txt в /tmp/my_data.txt если это ваш выходной файл.

Другие вопросы по тегам