🍎

Fileの変更を検知して特定のコマンドを実行するAppleScript

2022/11/10に公開

必要に駆られてタイトル通りの処理を定期的かつ自動で実行したかったので記録します。
AppleScriptを書くことが初めてだったので各処理の説明もかんたんにまとめておきます(備忘録です)。

何をする?

あるファイルの更新を検知して、特定のコマンドを実効するAppleScriptです。

結論

スクリプトは以下の通り。
日本語で記載している部分を自身の環境に合わせて変更すれば動くはずです。

copy_file_when_updated
property interval : 更新間隔(秒)
property checkedFilePath : 更新を検知したいファイルのパス
property mdate : ""

on run
    set mdate to (do shell script "date -r " & checkedFilePath & " +%Y:%m:%d:%H:%M:%S")
end run

on idle
    my main()
    return interval
end idle

on quit
    continue quit
end quit

on main()
    set mdate_new to (do shell script "date -r " & checkedFilePath & " +%Y:%m:%d:%H:%M:%S")
    if not mdate = mdate_new then
        display notification "detected modification"
        do shell script 特定のコマンド
        set mdate to mdate_new
    end if
end main

これをスクリプトエディタで保存します。
保存するときに、「ファイルフォーマット」を「アプリケーション」に設定し、「ハンドラの実行後に終了しない」をチェックする必要があります。


各処理の説明

1. 変数の定義

冒頭で必要な変数を定義します。
propertyで定義した変数はグローバル変数のように扱うことができるみたいです[1]

intervalcheckedFilePathは与えておきます。

property interval : 更新間隔(秒)
property checkedFilePath : 更新を検知したいファイルのパス
property mdate : ""

interval: 更新間隔。秒で指定しています。
例:property interval : 60

checkedFilePath: 更新を検知したいファイルのパス
例:property checkedFilePath : "/Users/stktu/Dropbox/xxx.txt"

mdate: 更新を検知したいファイルの更新日時を保存する変数

2. アプリの最初の実行時にファイルの更新日時を取得

on run
    set mdate to (do shell script "date -r " & checkedFilePath & " +%Y:%m:%d:%H:%M:%S")
end run

on メッセージ名からend メッセージ名までの部分をハンドラと呼びます[2]
runハンドラはアプリケーションを起動したときに実行されます。

dateコマンドで取得した更新日時をmdateに保存します。
intervalとの兼ね合いもありますが、1秒単位の更新も検知できるように、日時の文字列フォーマットは+%Y:%m:%d:%H:%M:%S(年:月:日:時:分:秒)で指定しています[3]

3. 一定間隔で繰り返し実行

on idle
    my main()
    return interval
end idle

idleハンドラは、何秒かおきにスクリプトを実行する場合に使います。[2:1]

アプリケーションを起動した直後と、その後interval秒ごとに指定したイベントが実行されます。
ここでは後述のmain()を実行します。

4. quitハンドラ

quitハンドラでは、必ずcontinue quitを書くと覚えておきましょう。[2:2]

とのことです。詳細は別の記事を参照してください。

on quit
    continue quit
end quit

5. ファイルの更新をチェック

on main()
    set mdate_new to (do shell script "date -r " & checkedFilePath & " +%Y:%m:%d:%H:%M:%S")
    if not mdate = mdate_new then
        display notification "detected modification"
        do shell script 特定のコマンド
        set mdate to mdate_new
    end if
end main

main()では以下の処理を行います。

  1. 検知対象のファイルの更新日時を取得してmdate_newに保存
  2. 予め取得しておいたmdatemdate_newとが異なれば、3–5を実行する。そうでなければ処理を終了する。
  3. "detected modification"という通知を表示する。
  4. 特定のコマンドを実行する。
  5. mdatemdate_newに置き換える。

mdate_newに保存される更新日時の形式はmdateと同じです。
監視対象のファイルが更新されたら、mdate_newmdateが異なっている(not mdate = mdate_newが真になる)ので、上記処理3–5が実行されます。

特定のコマンドはAppleScriptでもいいですし、コマンド、シェルスクリプトでも構いません。
例えば、監視対象のファイルをコピーするのであれば以下のように書きます。
(文字列は&で結合できます)

set newFilePath to ファイルのコピー先パス
do shell script "cp " & checkedFilePath & " " & newFilePath

さいごに

AppleScrpt、色々な操作を自動化できそうで便利だなと感じました。
はじめて書いたスクリプトなので、おかしい所やもっといい書き方があれば教えてもらえると嬉しいです。

脚注
  1. AppleScript の global 変数の使いどころ ↩︎

  2. 鳶嶋工房 / AppleScript / 入門 / ハンドラで受け止める ↩︎ ↩︎ ↩︎

  3. ファイルの更新日時を取得する方法 ↩︎

Discussion