Содержание статьи
INFO
Эта статья — уже третья из моего небольшого цикла о macOS. В первой («Обвес macOS») мы изучали скрытые настройки и собирали полезный софт, во второй («Кунг-фу для маковода») прошлись по большинству уникальных утилит командной строки. В ней я уже касался launchctl, но лишь вкратце. Что эта штука достойна отдельной статьи, было ясно сразу.
Благодаря гибкости настроек launchd, этот сервис заменил в macOS целый список более старых систем, которые пришли из Unix. Он управляет процессом загрузки ОС и сервисов (вместо init), он реагирует на подключения по сети (вместо inetd), он же запускает скрипты по времени (вместо cron) и при разных условиях. Мы воспользуемся этими богатыми возможностями для настройки всякой автоматизации: запуска скриптов по времени, срабатывания при помещении файла в папку, при изменении файла и при подключении внешнего носителя.
Я буду писать именно про launchctl, поскольку работаю в macOS, но если ты предпочитаешь Linux, то можешь позаимствовать идеи и скрипты, которые мы будем писать, и проделать все то же самое при помощи systemd. Эта система похожа на launchd и есть во многих современных дистрибутивах. Однако ее настройки в корне отличаются, и параллельно разбирать еще и их я не возьмусь.
Агенты и демоны
Файлы с правилами — это XML с расширением .plist. Внутри содержатся инструкции, которые указывают launchd, что и когда запускать. Эти файлы разложены в системе по пяти папкам:
~/Library/LaunchAgents
— агенты текущего пользователя;/Library/LaunchAgents
— агенты для всех пользователей;/Library/LaunchDaemons
— демоны для всех пользователей;/System/Library/LaunchAgents
— системные агенты (входят в состав macOS);/System/Library/LaunchDaemons
— системные демоны.
Отличие агентов от демонов довольно тонкое: демоны — это процессы, которые запускаются сразу после загрузки машины, а агенты могут работать только после логина в систему (соответственно, демонов для конкретного пользователя не бывает). К тому же демоны после активирования работают непрерывно, а агенты обычно срабатывают при определенных условиях.
Делать мы будем именно агенты и для личного пользования, так что первая папка из списка подойдет как нельзя лучше.
WWW
Для создания конфигурационных файлов launchd есть пара графических оболочек — LaunchControl и Lingon (обе стоят по десять долларов). Они слегка облегчают дело, но можно обойтись и без них.
Простой конфиг: запуск по времени
Начнем с самого простого — запуска чего-нибудь в определенное время. Вот как выглядит один из самых простых вариантов конфига.
<?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>название</string>
<key>ProgramArguments</key>
<array>
<string>путь к файлу</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key><integer>30</integer>
<key>Hour</key><integer>1</integer>
<key>Day</key><integer>6</integer>
</dict>
</dict>
</plist>
Несмотря на развесистый вид, структура здесь довольно несложная. Внутри основного словаря (<dict>
) идут ключи и следом — параметры к ним. Иногда это строки, иногда массивы, иногда вложенные словари.
Заменяй слово «название» на какое-нибудь название (обычно «com.домен.имя» — я, например, назвал тестовый агент com.and.launchtest
), укажи путь к исполняемому файлу в качестве первого параметра ProgramArguments
, а затем задай, во сколько и по каким дням запускать.
В примере выставлено время 1:30 каждую субботу. Если ты снесешь ключ Day
, скрипт начнет запускаться в половине второго каждую ночь, а если уберешь и Hour
, то каждые полчаса. Думаю, ты понял идею. Аналогичная запись в crontab выглядела бы как
0 30 1 * 6 <путь к файлу>
Если команда, которую ты запускаешь, принимает аргументы, то их нужно перечислить после пути, добавив дополнительные поля <string>
. Например:
<key>ProgramArguments</key>
<array>
<string>say</string>
<string>В Петропавловске-Камчатском полночь</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key><integer>0</integer>
<key>Hour</key><integer>15</integer>
</dict>
Когда все будет готово, сохраняем файл в ~/Library/LaunchAgents/
. Хорошей идеей будет сразу прописать в названии условия запуска, чтобы потом было легче ориентироваться. Например, мой тестовый конфиг я сохранил как com.and.launchtest.StartInterval.plist
.
Тонкости активации
К сожалению, обратная сторона гибкости — это развесистость настроек. Даже включать и выключать конфиги launchd можно несколькими способами. Вот старый и наиболее простой. Для загрузки пиши:
$ launchctl load -w ~/Library/LaunchAgents/<конфиг.plist>
И для выгрузки:
$ launchctl unload -w ~/Library/LaunchAgents/<конфиг.plist>
Ключ -w
заодно включает флаг enabled, что экономит нам один шаг (launchctl enable
) и сразу активирует конфиг. Помни, что после загрузки компьютера и входа в систему все агенты, лежащие в соответствующих папках, будут загружены автоматически. Именно поэтому при выгрузке удобно тоже добавлять -w
— тогда launchctl запомнит, что конфиг неактивен.
INFO
После того как что-то меняешь в конфиге, его нужно выгружать и загружать заново.
Можешь спокойно пользоваться этими командами, однако если откроешь man, то узнаешь, что они считаются устаревшими и поддерживаются лишь для совместимости. Более правильный способ — использовать команды bootstrap
и bootout
. Они требуют указывать, помимо пути к файлу конфигурации, domain-target, который состоит из домена и UID пользователя. Целиком команды будут выглядеть вот так:
$ launchctl bootstrap gui/<твой UID> <путь к файлу>
И для выгрузки:
$ launchctl bootout gui/<твой UID> <путь к файлу>
Узнать свой UID можешь командой id -u
. Первый пользователь компьютера обычно записан под номером 502.
Другая команда, которую хорошо помнить, — это list
. Чтобы проверить, какие из твоих конфигов загружены, можешь написать:
$ launchctl list | grep <название>
Опять же — существует более современный, более продвинутый и, конечно, более замороченный метод:
$ launchctl print <домен>/<UID>
На выходе будет куда больше информации, чем при запросе списка. Но опять же, использовать print
совершенно не обязательно. В ответ на вопрос о том, когда устаревшие команды перестанут работать, кто-то из разработчиков ответил на форуме, что на старый синтаксис слишком много завязано, чтобы убирать его.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»