ノート/Macメモ
visitors:   4067      last modified:   2008-08-20 (水) 13:51:35

Apple Script物語

スクリプトエディタを掘り出す(2008/08/13)

スクリプト実行環境は、少なくともOS 10.5にはデフォルトで入っているらしい。

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

do shell scriptで解決?(2008/8/14)

あちこち見ると、単純なUnix Command-line Applicationは、AppleScriptの "do shell script" で起動するのが簡単らしい。マニュアル:参照

サンプル:

do shell script "cd ~; ls"

をスクリプトエディタで試す。「実行」ボタンを押すと、スクリプトエディタの結果表示ウィンドウに結果が出てくる。

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

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

display dialogがある

display dialogというのがあるらしい。まずは試してみよう。スクリプトエディタで

set s to do shell script "cd ~; ls"
display dialog s

として、無理やり結果をダイアログに表示させてみる。まずはスクリプトエディタの 実行ボタンで確認。次に、ファイルにセーブして、Finder上でダブルクリックで確認。 shell_script1.png それらしい結果が出る。
ちなみに、Macで画面キャプチャは、command+shift+4 のあと、マウスで矩形選択、又はspaceを押した後、クリックでウィンドウを指定。デスクトップ?にPNGファイルが作られる。クリップボードにキャプチャしたいときは、control+command+shift+4。

コマンドリファレンス(AppleScript Language Guide: Commands Reference)で見てみる。

サンプルその1 〜 これをスクリプトエディタにコピペして実行したら、OK。 ここで、行末の「?」は、Macのキー「Option+lowercase L」で、継続行を示す。 マニュアル参照。

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

shell_script2.png

サンプルその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

結果の画面は、dialoganddocommand1.png dialoganddocommand2.png

もっといろいろできるらしい (2008/8/15)

コマンドスクリプトに入力ファイル名を与えたいことは、とても多いだろう。 専用の仕組が用意されていた。曰く choose file と choose file name である。

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

ファイル選択画面
choosefile1.png
選択したファイルに対してdo shell scriptでcatコマンドを実行した結果
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参照。前者は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)の「リスト」が戻される。 リストについてはマニュアルの「リスト」の項を参照。
5行目からのrepeat文は、文字列cに対して、リストのn番目の要素を(POSIXに変換して)アペンドしている。これは文字列の操作に当たるが、AppleScriptではtextクラスと呼んでいるようだ。同じマニュアルのtextの項を参照。
repeat直後に、do shell scriptで呼び出すcatコマンドの引数としてcのテキストを与えている。つまり、 結果として"cat file1 file2 file3 ..."のようなコマンド文字列をdo shell scriptしていることになる。

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

08/08/19 問題点発見

カレントディレクトリじゃない!!

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 更に問題が起こる

これで、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

おまけ〜プログラム配布? 


添付ファイル: filechoosemultifile2.png 664件 [詳細] filechoosemultifile1.png 666件 [詳細] filechoosefile2.png 648件 [詳細] filechoosefile1.png 707件 [詳細] filedialoganddocommand2.png 669件 [詳細] filedialoganddocommand1.png 704件 [詳細] fileshell_script2.png 671件 [詳細] fileshell_script1.png 691件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2008-08-20 (水) 13:51:35 (3350d)