[[ノート/Macメモ]]~
visitors:   &counter();       last modified:   &lastmod();

**Apple Script物語 [#u24c7204]

***スクリプトエディタを掘り出す(2008/08/13) [#o876ade8]
スクリプト実行環境は、少なくともOS 10.5にはデフォルトで入っているらしい。

スクリプトエディタは、アプリケーションの下のAppleScriptの下にある(スクリプトエディタ.app)。 こいつを起動すればいい。

***do shell scriptで解決?(2008/8/14) [#u3e67161]
あちこち見ると、単純なUnix Command-line Applicationは、AppleScriptの
"do shell script" で起動するのが簡単らしい。[[マニュアル::http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_cmds.html#//apple_ref/doc/uid/TP40000983-CH216-SW40]]参照

サンプル:
 do shell script "cd ~; ls"
をスクリプトエディタで試す。「実行」ボタンを押すと、スクリプトエディタの結果表示ウィンドウに結果が出てくる。

これを、コンパイルしておいて(必要?)、ファイル→保存→フォーマットをアプリケーションにして保存してみる。Finderでfoo.appをダブルクリック。起動するらしいが(画面が一瞬変わる)、何も表示しない。

当たり前だ。スクリプト上で、何も表示することになっていない。

***display dialogがある [#z6bb1eaf]
display dialogというのがあるらしい。まずは試してみよう。スクリプトエディタで
 set s to do shell script "cd ~; ls"
 display dialog s
として、無理やり結果をダイアログに表示させてみる。まずはスクリプトエディタの
実行ボタンで確認。次に、ファイルにセーブして、Finder上でダブルクリックで確認。
&ref(shell_script1.png);
それらしい結果が出る。~
ちなみに、Macで画面キャプチャは、command+shift+4 のあと、マウスで矩形選択、又はspaceを押した後、クリックでウィンドウを指定。デスクトップ?にPNGファイルが作られる。クリップボードにキャプチャしたいときは、control+command+shift+4。



コマンドリファレンス(AppleScript Language Guide: [[Commands Reference:http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_cmds.html]])で見てみる。

[[サンプル:http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_cmds.html#//apple_ref/doc/uid/TP40000983-CH216-SW12]]その1 〜 これをスクリプトエディタにコピペして実行したら、OK。
ここで、行末の「?」は、Macのキー「Option+lowercase L」で、継続行を示す。
[[マニュアル:http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/conceptual/ASLR_lexical_conventions.html#//apple_ref/doc/uid/TP40000983-CH214-SW9]]参照。
 set prompt to "Please enter password:"
 repeat 3 times
     set dialogResult to display dialog prompt ?
         buttons {"Cancel", "OK"} default button 2 ?
         default answer "wrong" with icon 1 with hidden answer
     set thePassword to text returned of dialogResult
     if thePassword = "magic" then
         exit repeat
     end if
 end repeat
 if thePassword = "magic" or thePassword = "admin" then
     display dialog "User entered valid password."
 end if
&ref(shell_script2.png);


[[サンプル:http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_cmds.html#//apple_ref/doc/uid/TP40000983-CH216-SW12]]その2 〜 これもスクリプトエディタにコピペして実行したら、OK。
(行末の「?」は、Macのキー「Option+lowercase L」で、継続行を示す。)
 set userCanceled to false
 try
     set dialogResult to display dialog ?
         "What is your name?" buttons {"Cancel", "OK"} ?
         default button "OK" cancel button "Cancel" ?
         giving up after 15 ?
         default answer (long user name of (system info))
 on error number -128
     set userCanceled to true
 end try
  
 if userCanceled then
     -- statements to execute when user cancels
     display dialog "User cancelled."
 else if gave up of dialogResult then
     -- statements to execute if dialog timed out without an answer
     display dialog "User timed out."
 else if button returned of dialogResult is "OK" then
     set userName to text returned of dialogResult
     -- statements to process user name
     display dialog "User name: " & userName
 end if
 end

これらのサンプルで分かることは、入力ができること。これで、ラインコマンドの
引数を入力する手段ができることになる。

上記のサンプル1を改造してやってみた。あまり丁寧に考えていない。とにかくできることを証明ればよいことにする。
(行末の「?」は、Macのキー「Option+lowercase L」で、継続行を示す。)
 set prompt to "Please enter filename:"
 set dialogResult to display dialog prompt ?
 	buttons {"Cancel", "OK"} default button 2 ?
 	default answer "wrong" with icon 1 with answer
 set fname to text returned of dialogResult
 
 if fname is "" then
 	display dialog "User entered empty filename"
 else
 	set s to do shell script "cd ~; ls " & fname
 	display dialog s
 end if
結果の画面は、&ref(dialoganddocommand1.png); &ref(dialoganddocommand2.png);

***もっといろいろできるらしい (2008/8/15) [#z1575dfd]
コマンドスクリプトに入力ファイル名を与えたいことは、とても多いだろう。
専用の仕組が用意されていた。曰く [[choose file:http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_cmds.html#//apple_ref/doc/uid/TP40000983-CH216-SW4]] と [[choose file name:http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_cmds.html#//apple_ref/doc/uid/TP40000983-CH216-SW5]] である。

choose fileは既存ファイルからの選択メニュー、choose file nameは新しくファイルを作るときに名前をどう付けますかという対話メニューである。

まずは、非常に単純なサンプルを作ってみる。
 set fname to choose file with prompt "Enter filename"
 
 if fname is "" then
 	display dialog "User entered empty filename"
 else
 	set s to do shell script "cat " & POSIX path of fname
 	display dialog s with icon 1
 end if

ファイル選択画面~
&ref(choosefile1.png); ~
選択したファイルに対してdo shell scriptでcatコマンドを実行した結果~
&ref(choosefile2.png);~

この例では選択した後、UNIXのcatで表示しようとしているが、その後に「POSIX path of fname」と
しているトリックがある。これは、MacOS上でのファイルオブジェクトを掴むときにaliasを使うのだが、
(表現としては「Hard_Disk:Applications.Mail.app」のようになる)、UNIX (POSIX) 上では
POSIX path を使う(「/Applications/Mail.app」)。([[マニュアルAliases and Files:http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/conceptual/ASLR_fundamentals.html#//apple_ref/doc/uid/TP40000983-CH218-SW28]]参照。前者はalias class、後者はPOSIX file pseudo-class
になっており、変換が必要になる。上記スクリプトでは、choose fileの出力のファイル名(alias形式)を
「POSIX path of」でPOSIX file形式に変換している。


複数ファイルの同時選択は、choose fileのオプションとして 「with multiple selections allowed」 を付けることによって実現できる。ついでに、promptを日本語文字列にしてみた。
 set fname to choose file with prompt ?
 	"複数入力ファイル選択" with multiple selections allowed
 if length of fname is 0 then
 	display dialog "User entered empty filename"
 else
 	set c to ""
 	repeat with n from 1 to length of fname
 		set f to POSIX path of (item n of fname)
 		set c to c & " " & f
 	end repeat
 	set s to do shell script "cat " & c
 	display dialog s with icon 1
 end if

前と同様、1行目行末の?は鉤の手文字で、継続行を示す。Commandキーを押しながら小文字のl(エル)。

この場合、choose fileの戻り値fnameには、ファイル名(alias)の「リスト」が戻される。
リストについては[[マニュアル:http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_classes.html#//apple_ref/doc/uid/TP40000983-CH1g-246384]]の「リスト」の項を参照。~
5行目からのrepeat文は、文字列cに対して、リストのn番目の要素を(POSIXに変換して)アペンドしている。これは文字列の操作に当たるが、AppleScriptではtextクラスと呼んでいるようだ。同じマニュアルのtextの項を参照。~
repeat直後に、do shell scriptで呼び出すcatコマンドの引数としてcのテキストを与えている。つまり、
結果として"cat file1 file2 file3 ..."のようなコマンド文字列をdo shell scriptしていることになる。

ファイル選択画面は~
&ref(choosemultifile1.png);~
複数選択は、コマンドキー(連番の場合はシフトキー)を押しながらマウスクリック。~
実行後のダイアログは~
&ref(choosemultifile2.png);~
3つのファイルがcatされている。

***08/08/19 問題点発見 [#l4abe91b]
カレントディレクトリじゃない!!

AppleScriptの中でdo shell scriptをすると、その時点でシェル(説明によると
bashらしい)が走り出す。問題は、そのシェルのカレントディレクトリが、
AppleScriptが走る(AppleScriptが置いてある)ディレクトリでは無い点である。

どうして問題か? こういうインストール構図を考えていた。~
AppleScriptと、C言語からコンパイルしたバイナリを、必ず同じディレクトリに置く
ようにする(させる)。そうすれば、フォルダ単位でインストールすれば、
お互い(AppleScriptとバイナリ)をどこにおいたかを気にせずに済む。なぜなら、
AppleScriptの中で、「カレントディレクトリにあるバイナリ」と言えばいいから。

(注:別に無理してカレントディレクトリを知らなくても、決めうちのディレクトリに
バイナリを置けばいいじゃないか。全くその通り。~
たとえば必ずバイナリを /Applications/ の直下にインストールする、と決めてしまえば、それで解決するのだが、どうも今ひとつ、この決めうちは好きになれない。
移動したら一発でこけるし。)

ところが、そうでなかった。UNIXだとshellからshellを起動すると子のシェルは
カレントディレクトリを継承する。ところがAppleScriptでは、do shell scriptが
思い込んでいるカレントディレクトリはルート(/)なのだった。

ググって見ると似たような経験をした人がいるようだった。そこでは、結局
Finderを使ってディレクトリを求める、という方法が提案されていた。~
試してみたのが次のような方法。

 tell application "Finder"
      get POSIX path of (folder of (path to frontmost application) as
           Unicode text)
 end tell
 set wd to result    --- result はその前のtellの結果
 ....
 set x to do sehll script wd & "fcs20ext" & c
    --- cには処理対象ファイル名が入っている(fcs20extのコマンドラインパラメタ)
 display dialog s with icon 1

これで、ファイルとしてセーブしたAppleScriptをダブルクリック起動すると
正しいカレントディレクトリが読める。

***08/08/20 更に問題が起こる [#lcb86f17]

これで、fcs20ext.app(AppleScriptをアプリケーションとしてセーブ)と
Cをコンパイルしたバイナリfcs20extを同じフォルダ内においてzip、サーバーに
アップした。そこからダウンロード・展開して、フォルダ全体を適当なところに置けば
インストール完了、という風にした。

さてこの通りインストールして実行してみると(AppleScript Editorは終了しておく)、
なぜか第1回目(インストール後初めて)fcs20ext.appをダブルクリックした時は、
カレントディレクトリが正しくセットされない。2回目からは問題ない。

問題は何か?1つ思いつくのは、第1回目に限りAppleScriptエディタが起動している。
エディタ内から起動すると、エディタがfrontmost applicationになってしまうので、
そのパスが拾われる。

ということで、パスを見つけるターゲットを、frontmost applicationではなくて、
ちゃんと自分自身(「application "fcs20ext"」 、実体はfcs20ext.appらしい)
を探して、そこへのパスにすることにする。
"application"はない方がいいのかも?(多分ファイルfcs20ext 〜 Cをコンパイル
したバイナリファイル 〜 を探してくれる??)

 tell application "Finder"
      get POSIX path of (folder of (path to application "fcs20ext") as
           Unicode text)
 end tell


***おまけ〜プログラム配布?  [#i9f85fb7]
-dmgファイル(dmg形式) → たとえば[[Mac OS X:ディスクイメージ(白いはんぺん)の基礎知識:http://homepage.mac.com/tsawada2/til/KB303.html]]
-Package Maker → [[Mac OSX のインストーラ作成ツール Package Makerを使う:http://nanasi.jp/others/packagemaker.html]]

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS