Рассмотрим ещё один интересный пример – эмуляция «cron». Crontab – системный сервис позволяющий запускать другие сервисы, службы или приложения по заданному расписанию (о нём я расскажу как-то в следующий раз). Сам по себе crontab напрямую не связан с launchd, однако при помощи ключа «StartCalendarInterval», заданного в конфиге, можно «заставить» launchd обрабатывать службы как crontab. Создадим файл с таким содержимым:
<?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>me.macdaily.getnewposts</string> <key>ProgramArguments</key> <array> <string>open</string> <string>http://macdaily.me</string> </array> <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>11</integer> <key>Minute</key> <integer>0</integer> </dict> </dict> </plist>
Данный сценарий будет открывать блог MacDaily.me, при помощи браузера указанного в системе по-умолчанию, каждый день в 11:00. Здесь стоит обратить внимание на вот эту часть кода:
<key>ProgramArguments</key> <array> <string>open</string> <string>http://macdaily.me</string> </array>
Как видно, в массиве заданы два параметра, которые аналогичны «терминальной» команде:
open http://macdaily.me
Каждый новый параметр указан в новом сегменте <string>параметр</string>. Для примера, чтоб системный голос Vicki произнёс текущее время нужно выполнить следующую команду:
say -v Vicki echo $(date "+%H:%M")
В преобразованном виде эта команда будет иметь следующий вид:
<key>ProgramArguments</key> <array> <string>say</string> <string>-v</string> <string>Vicki</string> <string>echo $(date "+%H:%M")</string> </array>
Можно задать и более жёсткие временные условия. Например, поставим напоминание поздравить блог MacDaily.me с днём рождения:
<?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>me.macdaily.happybirthday</string> <key>ProgramArguments</key> <array> <string>open</string> <string>http://macdaily.me/about/?yoursubject=HappyBirthday#mail-to-admin</string> </array> <key>StartCalendarInterval</key> <dict> <key>Month</key> <integer>4</integer> <key>Day</key> <integer>7</integer> <key>Hour</key> <integer>12</integer> <key>Minute</key> <integer>0</integer> </dict> </dict> </plist>
Данный сервис будет запускать браузер и открывать в нём страницу блога с контактной формой (для поздравления) 7 апреля каждого года в 12:00 по полудню. Разберём основные доступные подключи «StartCalendarInterval», и их параметры:
<key>Month</key> <integer>4</integer>
Month – указывает месяц для запуска сценария. Может принимать значение от 1 до 12.
<key>Weekday</key> <integer>0</integer>
Weekday – указывает день недели для запуска сценария. Может принимать значение 0, 1, 2, 3, 4, 5, 6, 7 (0 и 7 зарезервированы за воскресеньем). В связке с ключом Day служба будет запускаться только тогда, когда указанный в ключе день месяца будет совпадать с указанным в ключе Weekday днём недели.
<key>Day</key> <integer>7</integer>
Day – указывает день месяца для запуска сценария. Может принимать значения от 1 до 31.
<key>Hour</key> <integer>12</integer>
Hour – указывает время суток для запуска сценария. Может принимать значения от 0 до 23 (0 – полночь).
<key>Minute</key> <integer>0</integer>
Minute – указывает время в минутах для запуска сценария. Без указания ключей Month, Weekday, Day и Hour сценарий будет запускаться в указанные минуты каждого часа.
Но и это ещё не всё. Можно так же запускать какое-либо приложение с определённым интервалом времени, например:
<?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>me.macdaily.openeveryhour</string> <key>ProgramArguments</key> <array> <string>open</string> <string>http://macdaily.me</string> </array> <key>StartInterval</key> <integer>3600</integer> </dict> </plist>
Результатом работы данной службы будет открытие в браузере главной страницы данного блога через каждый час. За периодический запуск чего-либо отвечает ключ «StartInterval», который в секундах задаёт периодичность выполнения:
<key>StartInterval</key> <integer>3600</integer>
Пойдём далее…
Большое спасибо за отличную статью!
С удовольствием слежу за вашими постами.
Привет, Эд! Спасибо за отзыв. Раз уж iOS-разработчик так считает, значит не всё так плохо, как мне казалось 🙂
Ну это вы зря, бетенька 🙂
Честно, очень полезные статейки и хорошо все написано и объяснено.
Не смотря на то, что я занимаюсь разработкой под iOS, но разница все-таки есть между настольной системой, хоть и не большая. Поэтому с удовольствием заполняю пробелы в знаниях, что бы позже еще писать софт и под Mac OS.
Желаю творческих успехов! 😉
Ну спасибо 🙂 Ждём тогда какую-либо новинку под Mac OS X by Eduard Shalumov 😀
Клятвенно обещаю, как что-то сделаю под взрослую систему (MacOS), сразу кину на MacDaily!
Кстати, когда начну разработку ПО под мак, может вместе программку сварганим?
Ну хорошо. Очень интересное предложение, у меня даже есть парочка идей 😉
Вот как славно! Я тогда маякну как начну под мак писать 😉
ОК, жду 😉
Спасибо! Очень познавательно и полезно!
Благодарю за отзыв. То есть продолжать в подобном духе всё-же стоит? 😉
Конечно!! Иначе мы жутко расстроимся 😉
Вы еще спрашиваете? =)
Конечно стоит!
Мне как новичку не понятно о чем речь, но как написано понравилось :). Буду следить за продолжением.
Спасибо 🙂
сапсибо, уважаемые
Всегда пожалуйста 😉
Здравствуйте Александр!
У меня следующая проблема:
Мне нужно что бы следующий shell script выполнялся при старте системы:
Я написал следующий XML:
В логах вижу следующее:
Что я делаю неправильно? Заранее благодарен за помощь!
Всё равно слетает (:
Поместите код между тегами <pre></pre>.
<?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>random-seed</string>
<key>ProgramArguments</key>
<array>
<string>echo “Initializing kernel random number generator…”</string>
<string>if</string>
<string>[ -f /var/random-seed ];</string>
<string>then</string>
<string>cat</string>
<string>/var/random-seed</string>
<string>></string>
<string>/dev/urandom</string>
<string>fi</string>
<string>dd</string>
<string>if=/dev/urandom</string>
<string>of=/var/random-seed</string>
<string>count=1</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
О! ОК, утром разберусь, а то спать охота 😉
Ну да, при конвертации shell-скриптов в XML могут возникнуть некоторые непонятки. Можно попробовать вставлять или целостный скрипт, типа:
Или вот так ещё можно попробовать:
Но самое проще (чтоб не манаться с «угадываниями») – создать bash-скрипт, например random-seed:
И в XML (.plist) указать к созданному скрипту полный путь:
Естественно, скрипту random-seed нужно будет присвоит соответствующие права доступа и атрибуты.
Громадное Спасибо, попробовал последний вариант – вроде всё получилось ( в логах поиск строки random-seed ничего не находится – это правильно?)
И второй вопрос – Вы не знаете как сделать что бы скрипт выполнялся при ВЫХОДЕ из системы?
Ответе пожалуйста!
Да не за что. Проверить, отрабатывает ли скрипт, можно следующим способом. У вас в скрипте есть строка:
Но так как это echo будет запускаться через launchd то в Консоль ничего выводиться не будет (кроме ошибок). Модифицируйте скрипт таким образом:
И теперь все echo будут выводиться в Консоль. После перезагрузки запустите консоль и поищите слово «RandomSeed» или строку «Initializing kernel random number generator» в логах. Если они присутствуют – всё ОК, скрипт отрабатывает. Этот финт я использую как своего рода инструмент для отладки 😉
По поводу выполнения скриптов перед выходом/выключением/перезагрузкой… До версии 10.4 Tiger, и включая её, была очень простая возможность исполнять любое множество криптов, просто поместив их в соответствующую папку. С выходом следующих версий Mac OS X этот принцип изминили, и в текущих 10.7 Lion и 10.8 Mountain Lion для запуска logout-скриптов необходимо использовать хук. Работает это так:
1. Создадим shell-скрипт с нужными командами, например вот такой:
2. Сохраним его, к примеру, в системной папке /sbin под именем logout_hook и назначим ему правильные права доступа и атрибуты:
3. Теперь добавим хук:
Ну и попробуем… Я сам-то не пробовал, но, по идее, всё должно заработать.
Спасибо! Вроде всё работает!
Пожалуйста 😉
Оказывается я рано радовался:
—————————————–
Jun 16 22:08:01 MacBook.local loginwindow[343]: *** NSTask: Task create for path ‘/bin/customs_cripts/random-seed_Stop’ failed: 22, “Invalid argument”. Terminating temporary process.
—————————————–
random-seed_Stop:
=======================
LOGS=’RandomSeedStop’
(
echo “RandomSeedStop and I logout now…”
say -v Milena “Я Random Seed Stop, Я завершаю работу…”
# Сохранить источник случайности для генератора случайных чисел
# при завершении работы. Сохранить 512 байт, которые составляют
# пул энтропии для генератора случайных чисел.
echo “Saving random seed…”
dd if=/dev/urandom of=/var/random-seed count=1
) | logger -s -t $LOGS
=======================
Кто виноват и Что делать???
Покажите содержимое скрипта.
Так я же выше его привёл:
Во-первых, где #!/bin/bash вначале?
Во-вторых, если голосовые компоненты Milena будут отсутствовать в система – будет ошибка.
Лучше сделать так:
Огромное Вам спасибо за помощь и долготерпение!
Все получилось – виноват был отсутствующий #!/bin/bash
Не за что 😉 Рад, что у вас всё вышло 🙂
Здравствуйте, это опять я.
После обновления до 10.9.2 в консоли для RandomSeedStart (см.выше) вот такое сообщение:
20.03.14 1:33:57,305 locationd[73]: NBB-Could not get UDID for stable refill timing, falling back on random
Как это исправить?
Приветствую! Я догадался, что это снова вы 😉
Сложный вопрос… Проверил у себя – у меня всё работает (тоже 10.9.2). Я не совсем понимаю суть фразы «NBB-Could not get UDID for stable refill timing, falling back on random», но, по-моему, там идётся речь о том, что не получается получить UDID за определённый (выделенный) промежуток времени.
Попробуйте для начала при помощи Дисковой утилиты сделать проверку/восстановления диска (не прав доступа, а именно диска): Дисковая утилита → выбираете весь накопитель целиком → Первая помощь → Исправить диск. Потом сделайте то же самое для системного раздела (Macintosh HD). Для проверки/восстановления системного раздела, скорее всего, придётся загрузиться с Recovery HD. Отпишитесь, пожалуйста, о результатах 😉
Отписываюсь – ничего не изменилось.
На всякий случай вот файл.
Так это всего-лишь файл для автозапуска скрипта. У вас, судя по всему, скрипт отрабатывает правильно, проблема не в автозапуске, и не в скрипте. Проблема в том, что утилита dd не может вытянуть UDID из /dev/urandom, который, скорее всего, используется для генерации.
Подскажите пожалуйста, если сталкивались. Есть сервер слушающий порт принимающий запросы и отправляющий ответы. При простом запуске под пользователем работает всегда без проблем. Прекрасно запускается в виде демона из любого каталога при старте системы. Диагностика показывает что все работает как надо, порт открыт. По безопасности порт открыт, но принимать соединения отказывается. Клиент не видит его. В нормальный рабочий режим переходит только если его снять и его снова поднимет launchd. Дальше проблем больше не возникает. В plist’e прописывал sockets по мануалу, но тогда клиенты зависают намертво, а сервер соединения все равно не видит и не принимает. Перезапуск в данном поведении ничего не меняет.
Буду признателен за любую наводку так как в сети ничего найти пока не получилось. Да и применение Sockets разделов практически не рассматривается. Но точно знаю что есть ограничения по портам. Но опять же, какие…
Доброго дня, подскажите что это за процесс, как его убить, RunOuc , в поиске не могу прогуглить, когда он запущен “кушает 90%” процессора, mac book air ^ при этом греется сильно, и батарея быстро садиться, после перезагрузки на какое то время пропадает, а потом может опять появиться…
Спасибо заранее…
Приветствую! Нужно смотреть. Это процесс автозагрузки (по моему). То есть что-то после старта системы должно было запуститься, но оно зависло и «кушает» проц.
Добрый день. У меня выскочила вот такая ошибка. Делал действия на странице 2.
2014-09-25 22:31:19.259 Net Monitor[629:507] *** WARNING: -[NSImage compositeToPoint:operation:] is deprecated in MacOSX 10.8 and later. Please use -[NSImage drawAtPoint:fromRect:operation:fraction:] instead.
Программа не запускатся, и не перезапускается. Скрипт, полная копия вашего со второй страницы, только изменен путь к другому файлу.
Простите что без уточнения. У меня не запускается все в автоматическом режиме. И на данный момент у меня Maveriks 10.9.5