あるスクリプトを cron を利用して定期的に実行させたいなと思って調べたんだけど、どうやら OS X では cron は非推奨のようだ。替わりに Launchd というのを利用すれば同じような事が出来るらしい。さっそく使ってみる。
launchd とは
今回初めて聞いた言葉なのでとりあえずぐぐってみた。
Undocumented Mac OS X:第1回 initを置き換えるlaunchd【前編】 (2/3) - ITmedia エンタープライズTigerで採用されたlaunchdとは、initに代わって、最初に起動するPID 1のプロセスである。launchdは、initと同様端末の初期化やシェルを起動し、rcスクリプトの実行を処理する一方、OS起動時やユーザーのログイン時などにプロセスを起動する手段を提供する。それに加えinetd/xinetdと同じようにネットワークのポートを監視し、またcronのように指定時刻ごとにプロセスを立ち上げる。さらに、指定ファイルが編集されたり、指定ディレクトリにファイルが置かれたりするたびにプロセスを立ち上げるなどの手段も同時に提供する。
OS X を立ち上げたら一番最初に起動して OS 全体の制御を行う重要なプロセス、といった認識で良いんだろうか。
いろいろな機能があるようだが今回は cron の代わりとして利用する方法をメモしておく。
launchd を cron として利用する
launchd の機能では cron のようにある指定した日時になったら実行するもの, ある期間毎に実行するといった動作を指定する事ができる。
設定は plist ファイルで記述し、そのファイルはユーザのものは ~/Library/LaunchAgents/ 以下に配置する。launchd 用のディレクトリは他も合わせて以下のようなものがある。
- /System/Library/LaunchAgents
- /System/Library/LaunchDaemons
- /Library/LaunchAgents
- /Library/LaunchDaemons
- ~/Library/LaunchAgents
plist ファイルを作成したら launchctl コマンドで設定を読み込ませる必要があるがこれは後述する。
plist ファイルは何種類かフォーマットがあるらしいが他の plist ファイルに倣って xml で書いた。以下のような感じに書く。
<?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>example</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/ruby</string>
<string>/Users/ryomatsu/batch/example.rb</string>
</array>
<key>LowPriorityIO</key>
<true/>
<key>Nice</key>
<integer>1</integer>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>4</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
</dict>
</plist>
key とそれに続く値が一組になっている。なんだかわかりにくいのだがそういうものらしい。複数の値をいれる場合は array や dict を利用する。
設定するキーを簡単に解説。
Label | Launchd のジョブの名前。文字列でユニークな値をつける。 |
---|---|
ProgramArguments | 実行するプログラムとその引数。配列で指定できる。 |
LowPriorityIO | IO使用時の優先度低くてもよいかどうか。無くても良いらしい。 |
Nice | ジョブの優先度、だと思う。 |
StartCalendarInterval | 指定した日時に実行。 |
StartInterval | 一定時間毎に実行。 |
上記例では example.rb を毎日 4 時 30 分に実行するよう指定してある。指定の無い日などは cron でいう * と同じでワイルドカードとなる。さらに日や曜日などを指定する場合は以下のように指定できる。(曜日と日付を両方指定するのは実用的ではないと思うがあくまで例として)
<key>StartCalendarInterval</key>
<dict>
<key>Month</key>
<integer>4</integer>
<key>Weekday</key>
<integer>1</integer>
<key>Day</key>
<integer>10</integer>
<key>Hour</key>
<integer>8</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
日時の指定を複数書く場合は配列を利用できる。
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Hour</key>
<integer>12</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<dict>
<key>Hour</key>
<integer>18</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<dict>
<key>Hour</key>
<integer>8</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
</array>
integer の欄にはあくまで数値しか入力できないので cron のように / とか - を利用した指定はできない。ただし曜日だけは動作させたい曜日の数値を羅列できるっぽい。
launchd で一定時間毎に動作させたい
難しい事考えずに一定時間毎に動けば良い場合、上記表にも書いたが StartInterval を利用すると良い。
<key>StartInterval</key>
<integer>3600</integer>
これで一時間毎に動く。
設定した plist ファイルを Launchd へ登録する
作成した plist を launchd で動かすには launchctl コマンドを利用する。load で読み込み、 unload で読み込み解除する。
$ launchctl load ~/Library/LaunchAgents/example.plist
$ launchctl list
- 0 example
$ launchctl unload ~/Library/LaunchAgents/example.plist
launchctl list に表示されているならちゃんと時間になったら実行されるはずだ。