launchdの作業ディレクトリ(Lingon 3を使ってplist作成)

おことわり

Yosemiteにしたあとで若干変更が必要になったので追記しました(2015/8/31)。

では

最近のMac OS Xはcronで繰り返し実行をさせるのではなく、launchdを使って実行させます。

その設定ファイルなんたら.plistは以下のディレクトリに登録します。

~/Library/LaunchAgents
/Library/LaunchAgents
/Library/LaunchDaemons
/System/Library/LaunchAgents
/System/Library/LaunchDaemons

LaunchDaemons (launchctl, launchd.plist) の使い方 - maruko2 Note.

launchdのplistの作成は面倒

なのでLingonを使います。

Lingon 3 App

カテゴリ: ユーティリティ

価格: ¥250

Lingonでの設定ファイルは

~/Library/LaunchAgents

に入ります。ここに設定ファイルを登録したときはlaunchdでの実行ではなくログインユーザでの実行です。

launchdで実行するときには

ここで大事なこと。

  • 実行ユーザはログインユーザhoge
  • 作業ディレクトリはルート/
  • .bashrc .bash_profile 見てないから homebrew でいれたコマンドへPATHが通ってない
  • 設定ファイルのパーミッション755(大事なことなので二度書きました)

これを分かっていなくて、見当外れのデバッグをしてました。
具体的には、作業ディレクトリに依存するスクリプトを書いてしまい、とても難儀しました。
気をつけなきゃ。

気をつけない方法

気をつけなきゃ、と言ってるのにそれを覆してみるw

  • 実行ユーザはログインユーザhoge

逆に言えばログインユーザで実行したいのでこれは置いておく。

Lingonでは設定できませんが、~/Library/LaunchAgents/にあるplistファイル(Lingonでの登録名。例:foobaa.plist)をテキストエディタで開けば変更可能*1

(前略)
  <key>WorkingDirectory</key>
  <string>/usr/local</string>
(後略)

LaunchAgentsで標準出力・エラー出力を設定する - Aerialarts

これと同様にkeyに"WorkingDirectory"、stringに作業ディレクトリを書いたセットをfoobaa.plistに追記すればOKです。

  • .bashrc .bash_profile 見てないから homebrew でいれたコマンドへPATHが通ってない

cronだとPATH通ってないと分かってるのでコマンドをフルパスで書きますけど、ログインユーザで実行してると思うとPATHが通っていると思うじゃありませんかw
では.bashrc .bash_profile を見させ /usr/local/binにPATHを通しましょうw
なお bash のオプションに -c というのがあります。

オプション

-c string
-c オプションが指定されると、コマンドが string から読み込まれます。 string の後に引き数があれば、これらは 位置パラメータ (positional parameter: $0 から始まるパラメータ) に代入されます。
Man page of BASH

その1:
sh -c "source ~/.bash_profile; 〜コマンド〜"
sh -c "PATH=/usr/local/bin:$PATH; 〜コマンド〜"

そしてfoobaa.plistのほうに

  <key>WorkingDirectory</key>
  <string>/Users/hoge</string>

Rubyスクリプトを使っている場合には

を参考にして Dir.chdir で作業ディレクトリを移動させることも出来ますね。

Dir.chdir(File.dirname(File.expand_path(__FILE__)))
その2:(こちらだと作業ディレクトリが移動しない)
sh -c "source /Users/hoge/.bash_profile; 〜コマンド〜"
sh -c "PATH=/usr/local/bin:$PATH; 〜コマンド〜"

どちらかの方法で.bashrc .bash_profile を読み込ませれば、homebrewへのPATHも見てくれますので後はラクラクです♪

手動でのplist修正後はそのplistを読み込ませましょう

$ launchctl unload ~/Library/LaunchAgents/foobaa.plist

してから

$ launchctl load ~/Library/LaunchAgents/foobaa.plist

しましょう。
なお、rubygemsのlunchyを使うと、若干ですがplistの読み込みなどを分かりやすく扱えます。
lunchy lsでplistの名前を確認してから実行してみましょう。

$ lunchy ls
com.apple.FolderActions.enabled
com.apple.FolderActions.folders
foobaa

一旦止めてから読み込ませます。

$ lunchy stop foobaa
stopped foobaa
$ lunchy start foobaa
started foobaa

Rubyネタおまけ

Rubyコマンドラインオプションで"-C"というのがあります。作業ディレクトリの変更を意味します。

コマンドラインオプション

-C directory
スクリプト実行前に指定されたディレクトリに移動します。
るりま:Rubyの起動

launchdネタおまけ:独立したlog

launchdのlogはコンソールの「すべてのメッセージ」で確認できます。 Lionでは出力されていましたが、Yosemiteでは出力されないようになったようです。
が、独立logファイルを作ることも出来ます。
先ほど紹介したサイトを再度引用します。

  <key>StandardOutPath</key>
  <string>/usr/local/var/log/memcached.log</string>
  <key>StandardErrorPath</key>
  <string>/usr/local/var/log/memcached.log</string>

LaunchAgentsで標準出力・エラー出力を設定する - Aerialarts

これに従った書き方をして、適当な場所を指定してあげれば、それだけでOKです。とても簡単。
#追記:logファイルが存在していない場合には作っておく必要があります。つまりtouchしておくこと。
なお、この他のkeyに関しては
http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/launchd.plist.5.html
をご覧くださいませ。



補足:スクリプト側でlog書くのもアリだと思うよ!
スクリプトの時刻付きログ出力メソッド - 別館 子子子子子子(ねこのここねこ)はてブロ部

*1:plistの記載が面倒だからLingonを使う、と言っていたのに、とか言わないようにw