ドラッグ&ドロップでフォルダを同期するフォルダアクション [プログラミング]
大学で作業していてちょっとしたことだけど、面倒だったことがあった。作業場では古いMac mini(core solo)を置いていくつかの装置の制御や、作業に使うユーティリティや、データのメモに使っている。ところがその部屋は独立した建家にあって、ネットワークがない。そこでUSBのフラッシュメモリを使って、居室のMac mini(mid 2010 Core2Duo)とファイルのやりとりをしている。絵にすると
こうである。絵にするようなものでもないけど。
居室のMac miniは震災前会社で仕事に使っていたやつで、居室では学内のネットワークに繋がっていて、DropBoxなんかを経由して榴岡のiMacにバックアップするようになっている。
最初のうちはフラッシュメモリに丸コピーしてたんだけど、ファイル数が増えてきてどれがコピーすべきファイルなのかわからなくなってきたので、フォルダをまるごとrsyncコマンドで同期するようにした。それでもいいんだけどいちいちターミナルを開いてrsyncを打ち込むのも面倒になってきた。こういうときは「フォルダアクション」でドラッグ&ドロップですぐ同期、だろうと思った。
そういうのってきっと誰かがやってるだろうと思って、ウェブで探してみたんだけどなかなか見つからない。しょうがない、では自分で書くか、と思い立ったけど、これまでフォルダアクションも、それを記述するためのApple Scriptも使ったことなかったので、実際にやってみるとけっこう苦労した。
きっかけになるユーザの操作というのは
「フォルダアクション設定」と言うアプリは「どのフォルダに」「どのApple Script」を結びつけるか、という指示と、そのアクションを有効にするかどうかを設定する。Apple Scriptは「スクリプトを編集」というボタンがあって、それを押すと「Apple Scriptエディタ(/Applications/Utilities/AppleScript Editor.app)」が開く。デフォルトでフォルダに画像ファイルが追加されるとその形式をJPEGやPNGに変換してコピーするといったようなほとんどサンプルレベルのスクリプトが13個ある。新しくフォルダアクション用のスクリプトを書くには「Apple Scriptエディタ」アプリで書いて決まったフォルダに入れておく。
決まったフォルダというのは
この「フォルダアクション」の機能を使って、フォルダに別のフォルダをドラッグ&ドロップしたときrsyncが起動するようにすれば簡単だろう、と思った。
ということで、地道に Apple Scriptのドキュメントを読むことにした。
斜め読みしながらサンプルなんかを動かしてるうちに、これはけっこう面白いかも、と思うようになった。unixのshell scriptなんかと違ってかなり整理されている。unixのshell scriptはもともとコマンドを組み合わせてひとつのコマンドにするためのもので、コマンドの階層化と自動化が主な目的だった(unixのコマンドは伝統的に簡単な作業をするコマンドをいくつか書いて、それらをつなぎ合わせて目的を達成する、というスタイルが使われる。/binや/usr/binにあるコマンドはすべてそういう思想で作られている)。したがってプログラミング言語としての問題意識は低い。つまり、ガタガタ言わずまず動かす、と言う仕様のように思える。
一方のApple Scriptはプログラミング言語であることを意識しているように思える。プログラミング言語としては、次のふたつのポイントを持っている。
異なるオブジェクトでも似た動作を表すのになるべく同じ単語が使われるようになっているし、継承の機能も持っている。継承はプログラミングの機能というよりは組み込みのスクリプトを整理してわかりやすくするためのように見える。
また、英語の文章に見えるようにするためにかなりの労力が払われている。そのまま英語として読めるわけではないけど、たとえば膨大なキーワード(予約語)を持っていて、「the」と言うキーワードはプログラミング上は無視されるけど読みやすくするために普通の英語と同じような位置に挟むことができる。あまりにキーワードが多いので、プログラミングのときには変数名と衝突しないように気をつけるのが煩わしいけど。
文字列や数やリストといった「型」はあるけど、スクリプト言語らしく変数はどんな型でも代入できる。また変数は宣言する必要はなく、変数が初めて現れる文に実行がたどり着いた時点でそれが作られる。
アプリの制御はApple Eventを通じて行われる。Apple EventはMac OS Xの高レベルプロセス間通信で、たとえばFinderはファイルやフォルダに対していろいろな操作ができるように膨大なApple Eventが定義されている。Apple Scriptの字面の上ではスクリプト本体の処理と、Apple Eventの発行受信とは区別がないように工夫されている。つまり、プログラマはApple Eventを気にせず、単にFinderなどのアプリがApple Scriptの機能を拡張しているとみなせるようになっている。実は微妙な制限があるけど、非常によくできている。
また、ファイルを指定するためにはfileというオブジェクトとaliasというオブジェクトのふたつがある。これがわかりにくい。最初僕はこのaliasを、エイリアス(Finderの「ファイル」メニューの「エイリアスを作成」でできるシンボリックリンクみたいなやつ)だと思い込んで、全然意味が分からなかった。もちろん別物。
このfileとaliasは、機能はほとんど同じなんだけど、新しいファイルを作るときはfileオブジェクトでないといけない。aliasというのはファイルの場所を移動しても同じものを指し続けることができるという特徴があるので、既存のファイルを読み書きするときは便利だという。区別している意味がよく分からない。aliasはHFSファイルシステムがufsのi-nodeと違ってノード番号を再利用しない、という特徴を利用したものだと思われるが、FATやufsをマウントしたときどうなるのかはよくわからない。
そして、Apple Scriptの最大の問題点といえるのが、遅い、ということ。多くの動作をApple Eventというプロセス間通信を経由して行うので、これはある程度しかたがないことなんだけど、簡単な作業でもひと呼吸して、やっと結果がかえってくるという感じになる。さらにフォルダアクションになると、さらにもうふた呼吸しないと作業が終わらない。
もうひとつは「フォルダアクション」の動作はどれもユーザが何かした「後に」起動されるということ。ドラッグの最中には呼べないし、ドロップしてしまうとFinderが移動と解釈してそれを実行してしまったあとに「フォルダアクション」が呼ばれることになる。こっちはなんらかのアイデアがないと致命的で、フォルダアクションとしては実現できない、ということになる。
ということで、長くなりすぎたので、続きは次回。次は実際に動くフォルダアクションを示す。
こうである。絵にするようなものでもないけど。
居室のMac miniは震災前会社で仕事に使っていたやつで、居室では学内のネットワークに繋がっていて、DropBoxなんかを経由して榴岡のiMacにバックアップするようになっている。
最初のうちはフラッシュメモリに丸コピーしてたんだけど、ファイル数が増えてきてどれがコピーすべきファイルなのかわからなくなってきたので、フォルダをまるごとrsyncコマンドで同期するようにした。それでもいいんだけどいちいちターミナルを開いてrsyncを打ち込むのも面倒になってきた。こういうときは「フォルダアクション」でドラッグ&ドロップですぐ同期、だろうと思った。
そういうのってきっと誰かがやってるだろうと思って、ウェブで探してみたんだけどなかなか見つからない。しょうがない、では自分で書くか、と思い立ったけど、これまでフォルダアクションも、それを記述するためのApple Scriptも使ったことなかったので、実際にやってみるとけっこう苦労した。
フォルダアクション
「フォルダアクション」というのは、Mac OS Xの機能のひとつで、特定のフォルダに対してユーザが何かしたら、それをきっかけになんらかの作業を自動的に行う、というもの。前もってどのフォルダで何をするかを設定する。設定はフォルダを選択してコンテクストメニューから行う。実際の設定は「フォルダアクション設定(/System/Library/CoreServices/Folder Actions Setup.app)」というアプリを使って、フォルダにApple Scriptを結びつける。この機能がいつから搭載されていたのか忘れたけど、けっこう古い。きっかけになるユーザの操作というのは
- フォルダにファイルを追加した
- フォルダからファイルを削除した
- フォルダのウィンドウを開いた
- フォルダのウィンドウを閉じた
- フォルダのウィンドウを動かしたりリサイズした(デベロッパサイトのドキュメントにはNot currently available.となっている)
「フォルダアクション設定」と言うアプリは「どのフォルダに」「どのApple Script」を結びつけるか、という指示と、そのアクションを有効にするかどうかを設定する。Apple Scriptは「スクリプトを編集」というボタンがあって、それを押すと「Apple Scriptエディタ(/Applications/Utilities/AppleScript Editor.app)」が開く。デフォルトでフォルダに画像ファイルが追加されるとその形式をJPEGやPNGに変換してコピーするといったようなほとんどサンプルレベルのスクリプトが13個ある。新しくフォルダアクション用のスクリプトを書くには「Apple Scriptエディタ」アプリで書いて決まったフォルダに入れておく。
決まったフォルダというのは
- Library/Scripts/Folder Action Scripts/
- $HOME/Library/Scripts/Folder Action Scripts/
この「フォルダアクション」の機能を使って、フォルダに別のフォルダをドラッグ&ドロップしたときrsyncが起動するようにすれば簡単だろう、と思った。
Apple Script
実は、僕はApple Scriptをまったく使ったことがない。僕はスプリプト言語が苦手で、unixのshell scriptでさえ、いまだかつて数行以上のものを書いたことがない。unixの場合は文法がわかりにくいのと、さらにshellによって(sh、csh、bash、ksh....)文法が違っていて全然覚えられない。結局Cで書いてコンパイルして実行させるほうが早い、という場合ばかりだった。ということで、地道に Apple Scriptのドキュメントを読むことにした。
斜め読みしながらサンプルなんかを動かしてるうちに、これはけっこう面白いかも、と思うようになった。unixのshell scriptなんかと違ってかなり整理されている。unixのshell scriptはもともとコマンドを組み合わせてひとつのコマンドにするためのもので、コマンドの階層化と自動化が主な目的だった(unixのコマンドは伝統的に簡単な作業をするコマンドをいくつか書いて、それらをつなぎ合わせて目的を達成する、というスタイルが使われる。/binや/usr/binにあるコマンドはすべてそういう思想で作られている)。したがってプログラミング言語としての問題意識は低い。つまり、ガタガタ言わずまず動かす、と言う仕様のように思える。
一方のApple Scriptはプログラミング言語であることを意識しているように思える。プログラミング言語としては、次のふたつのポイントを持っている。
- オブジェクト指向的な考え方を取り入れている 字面が普通の英語の文章に見えるように細かな工夫がされている
異なるオブジェクトでも似た動作を表すのになるべく同じ単語が使われるようになっているし、継承の機能も持っている。継承はプログラミングの機能というよりは組み込みのスクリプトを整理してわかりやすくするためのように見える。
また、英語の文章に見えるようにするためにかなりの労力が払われている。そのまま英語として読めるわけではないけど、たとえば膨大なキーワード(予約語)を持っていて、「the」と言うキーワードはプログラミング上は無視されるけど読みやすくするために普通の英語と同じような位置に挟むことができる。あまりにキーワードが多いので、プログラミングのときには変数名と衝突しないように気をつけるのが煩わしいけど。
文字列や数やリストといった「型」はあるけど、スクリプト言語らしく変数はどんな型でも代入できる。また変数は宣言する必要はなく、変数が初めて現れる文に実行がたどり着いた時点でそれが作られる。
アプリの制御はApple Eventを通じて行われる。Apple EventはMac OS Xの高レベルプロセス間通信で、たとえばFinderはファイルやフォルダに対していろいろな操作ができるように膨大なApple Eventが定義されている。Apple Scriptの字面の上ではスクリプト本体の処理と、Apple Eventの発行受信とは区別がないように工夫されている。つまり、プログラマはApple Eventを気にせず、単にFinderなどのアプリがApple Scriptの機能を拡張しているとみなせるようになっている。実は微妙な制限があるけど、非常によくできている。
Apple Scriptの気になる点
Apple Scriptは古いMac OSからの機能なのでレガシーな部分もある。例えばファイルの指定はデフォルトではunixのパスではなくコロンを使ったMacintosh HD:Useres:decafish:Documents:targetFile.txtなどという古い指定が使われる。この場合起動ディスクのボリューム名を知らないと絶対パスが作れない。unix風の
/Useres/decafish/Documents/targetFile.txtとくらべると一手間必要になる。もちろんこれは相互変換できるようになっているが、内部形式は古いほうである。そういう古くさい感じがぽつりぽつりとある。
また、ファイルを指定するためにはfileというオブジェクトとaliasというオブジェクトのふたつがある。これがわかりにくい。最初僕はこのaliasを、エイリアス(Finderの「ファイル」メニューの「エイリアスを作成」でできるシンボリックリンクみたいなやつ)だと思い込んで、全然意味が分からなかった。もちろん別物。
このfileとaliasは、機能はほとんど同じなんだけど、新しいファイルを作るときはfileオブジェクトでないといけない。aliasというのはファイルの場所を移動しても同じものを指し続けることができるという特徴があるので、既存のファイルを読み書きするときは便利だという。区別している意味がよく分からない。aliasはHFSファイルシステムがufsのi-nodeと違ってノード番号を再利用しない、という特徴を利用したものだと思われるが、FATやufsをマウントしたときどうなるのかはよくわからない。
そして、Apple Scriptの最大の問題点といえるのが、遅い、ということ。多くの動作をApple Eventというプロセス間通信を経由して行うので、これはある程度しかたがないことなんだけど、簡単な作業でもひと呼吸して、やっと結果がかえってくるという感じになる。さらにフォルダアクションになると、さらにもうふた呼吸しないと作業が終わらない。
とりあえず解決すべき問題
とりあえずふたつの問題が思い浮かんだ。ひとつめはApple Scriptは面白そうなんだけど、やっぱりあまり慣れ親しんでないので簡単な言い回しを知らずに、冗長なコードを書く可能性が高い、ということ。もうひとつは「フォルダアクション」の動作はどれもユーザが何かした「後に」起動されるということ。ドラッグの最中には呼べないし、ドロップしてしまうとFinderが移動と解釈してそれを実行してしまったあとに「フォルダアクション」が呼ばれることになる。こっちはなんらかのアイデアがないと致命的で、フォルダアクションとしては実現できない、ということになる。
ということで、長くなりすぎたので、続きは次回。次は実際に動くフォルダアクションを示す。
2012-10-24 22:52
nice!(0)
コメント(0)
トラックバック(0)
コメント 0