ShellScript
Bash
MacOSX
AppleScript

2ステップでシェルスクリプトをOS Xアプリケーションに

More than 5 years have passed since last update.

以前、シェルスクリプトを OS X アプリケーションにする方法を書いたんですが、微妙だったので削除しました。

で、新しいのを。

例として Wine を実行するシェルスクリプトです。

echo | osacompile -o foo.app
echo '#!/bin/bash
/opt/local/bin/wine explorer' > foo.app/Contents/MacOS/applet

内容は、

  1. osacompile で空のアプリケーションバンドルを作成する
  2. バンドル内の applet をシェルスクリプトに書き換える

だけです。osacompile は AppleScript をアプリケーションバンドル化したりするコマンドですが、この例では AppleScript を使わないので空の状態で作成します。osacompileContents/MacOS 以下に applet というファイルを作成します(open ハンドラ使用時は droplet)。これは Contents/Resources/Scripts/main.scpt を呼び出すバイナリですが、これをシェルスクリプトに置き換えてしまいます。このファイルには既に実行権限がついているので chmod は不要です。

foo.app
└── Contents
    ├── Info.plist
    ├── MacOS
    │   └── applet(Info.plist によって呼ばれる実行ファイル)
    ├── PkgInfo
    └── Resources
        ├── Scripts
        │   └── main.scpt(本来 applet によって呼ばれる AppleScript)
        ├── applet.icns
        └── applet.rsrc

Mac OS のアプリケーションバンドルはただのフォルダなので、

  • Contents/Info.plist
  • Contents/MacOS/executable

の2つがあれば実行できます。Info.plist の作成が面倒なので今回は osacompile で自動生成させたものを使用しています。executable のファイル名に関しては Info.plist 内の CFBundleExecutable で変更できます。

Contents/Resources 以下には本来のコンテンツ(AppleScript やアイコン等)がありますが、これに関しては Resources フォルダごと削除してしまってもかまいません(アイコンは空になりますが)。


以下おまけ。


上の方法だと若干無理矢理なので、AppleScript からシェルスクリプトを実行する本来の方法も書いておきます。これなら1ステップです。

osacompile はパイプからの入力も処理できるのでシェルスクリプト部分は echo でも書けますがダブルクオートの処理が面倒なのでヒアドキュメントを使うのが無難かなと思います。

try 文は必須ではないですが、シェルスクリプトの結果がエラーになると場合によってはとてつもなく長いエラーウィンドウが表示されるので用途に応じて。この AppleScript は Contents/Resources/Scripts/main.scpt として保存されます。

osacompile -o foo.app <<__APPLESCRIPT__
try
    do shell script "/opt/local/bin/wine explorer"
end try
__APPLESCRIPT__

外部スクリプト実行形式

AppleScript 内でのダブルクオートのエスケープ等が面倒な場合は別のシェルスクリプトを作成して外部スクリプトとして実行させるといいかもしれません。AppleScript では Contents/Resources 内にあるファイルのフルパスを path to resource "filename" で取得できます。ファイルパスは alias で返って来るので POSIX パスに変換し、スペース対策として quoted form をかけておきます。

do shell script quoted form of POSIX path of (path to resource "script.sh")

上のコードは以下のように変換されます。

do shell script '/path/to/foo.app/Contents/Resources/script.sh'

まとめるとこんな感じ。

osacompile -o foo.app <<__APPLESCRIPT__
try
    do shell script quoted form of (POSIX path of (path to resource "script.sh"))
end try
__APPLESCRIPT__
echo '#!/bin/bash
/opt/local/bin/wine explorer' > foo.app/Contents/Resources/script.sh
chmod +x foo.app/Contents/Resources/script.sh

ヒアドキュメント内に変数使ったり、do shell script 内で改行して書いてもOK(インデントは取り除かれるけど)。

以下は Finder の不可視ファイルの表示を切り替えるアプリケーション作成用のスクリプトの例。

domkey="com.apple.finder AppleShowAllFiles"
osacompile -o HiddenFileSwitch.app <<__APPLESCRIPT__
do shell script "
    case \$(defaults read ${domkey}) in
        0) x=TRUE;;
    esac
    defaults write ${domkey} -bool \${x-FALSE}
    killall Finder
"
__APPLESCRIPT__

kill されるまで動き続けるシェルスクリプトを直接または do shell script で実行すると Dock アイコンが「応答なし」になります。これはバックグラウンドで動かして quit ハンドラを使って kill するといいかもしれません。以下にサンプルを置いておきます。

https://github.com/mattintosh4/AppleScript/blob/master/MediaTombLauncher.applescript