アレしたあとにコレしたい!

tag perl

こんにちは。罪悪感でちょっとムネがチクチクするhirose31です。

アレしたあとにコレする

「ファイルが変更されたらXXXしたい」ということは日常よくあるんじゃないかと思います。例えば:

などなど。

今までは、Linux の Inotify という機能を Perl から使うためのモジュールLinux-Inotify2を使ったスクリプトを書いて使っていたのですが、とりあえずぼへらっと書いたものだったので、

というイケてない点がありました。

というわけで、今回書き直したのがこれです:

Filesys-Notify-Simpleを使っているので、LinuxだけでなくMac OS Xなどでも動くと思います。

observe-file

機能的には、ファイルもしくはディレクトリを監視対象に指定でき、ファイルが追加、変更、削除されたら、これも予め指定しておいた任意のコマンドラインを実行する、といったスクリプトです。

使用例をいくつか紹介します。

スクリプトを保存したら実行する

例えば「foo.pl」というスクリプトを今書いていて、保存したら試しに動かしてみたいのですぐ実行したい、といった場合にはこのようにします。

observe-file -c ./foo.pl ./foo.pl

実行時にオプションを指定したり、もうちょっと複雑なコマンドラインを実行したい場合は、-cの値をクォートで囲えばOKです。

observe-file -c 'perl -wc foo.pl && ./foo.pl -v -c test.conf' ./foo.pl

ちなみに、最初の例のように監視対象がひとつのファイルでそれが実行するコマンドと同一の場合はこのようにも指定できます。

observe-file -x ./foo.pl

コンテンツファイルに変更があったらブラウザをリロードする

FirefoxにMozReplをインストールすると、ブラウザ外から(許可すれば別ホストからでも)JavaScriptでブラウザを操作できるようになります。

このMozReplを使えば、こんなスクリプトを用意しておくことで、

#!/bin/sh
# ~/bin/reload-firefox

[ $# -eq 1 -o $# -eq 2 ] || { echo 'usage: reload-firefox HOST [PORT]'; exit 1; }
host=$1
port=${2:-4242}

echo "reload: $host:$port"
cat <<EOF | nc $host $port
content.location.reload(true)
repl.quit()
EOF
echo

ブラウザをリロードすることができます。

$ reload-firefox coupe

さてこのreload-firefoxとobserve-fileを組み合わせれば、webappのコードやHTML、CSS、JavaScriptのファイルに変更があったら自動でブラウザをリロードすることもできます。

observe-file -c 'reload-firefox coupe' app/ static/ tmpl/

注意点

MacでMac::FSEventsが使える場合に、配下に大量のファイル/ディレクトリがあるディレクトリを監視対象として指定した場合や、監視対象としてファイルを指定したときにその親ディレクトリ配下の大量のファイル/ディレクトリがあると、場合によってはまともに使えないほどに動作に時間がかかる可能性があります。

例えば、ホームディレクトリ直下の t.pl を自動実行しようと

$ observe-file -x ~/t.pl

とした場合に、ホームディレクトリ配下に多くのファイルなどがある(と思います)ようなケースです。このような場合は、新しくサブディレクトリを作ってその下に監視対象のファイルやディレクトリを置いて、observe-fileを使うようにしてください。

ちなみにこれは、MacのFSEventがディレクトリ単位でしか監視対象にできないという仕様に起因するものです。ですので、LinuxでInotifyの場合は、Inotifyはファイル単位でも監視できるので全く問題ないです。