(-> % read write unlearn)

All opinions expressed are solely my own and do not express the views or opinions of my employer.

gulp.watchみたいな「ファイルの変更を検知して何かする」をShellで手軽にやりたい

gulp watchすれば良いんだけど、そのためだけにNodeやgulpを登場させないといけないのがちょっと嫌です。ググったらShellでそういう機能を書いてる人がいました。

次のようなことを対応したかったので、上記を参考に書いてみました。

  • OSXにはls -l --full-timeが無いようなので違うコマンドでファイルの更新日時を取得する。
  • 複数ファイルを監視する。
  • 監視自体は複数ファイルを対象にしても、実行するコマンド自体は変更があったファイルのみを対象にできる。

gulp.watchみたいにファイルの変更を検知して何かする

Usage

$ watch-files
Usage:
        第一引数: 監視対象ファイルが更新された際に実行されるコマンド
        第二引数以降: 監視対象ファイルのリスト
        例: watch-files 'cargo build && cargo run' ./src/*.rs
            watch-files 'mermaid -sp $_f' ./*.mermaid
  • *とか[foo,bar].cppとかのように複数ファイルを指定してもいいし、単純に第二引数以降にファイル名を列挙してもいいです。
  • 環境変数
    • INTERVALで変更監視の間隔を指定できます(秒)。
      INTERVAL=3 sh watch-files 'echo $_f is modified!' ./*.txtみたいな感じです。
  • 第一引数のコマンド内で使える変数
    • $_f: 変更があったファイル(例:foo.mermaid*1
    • $_last: 変更があったファイルの以前の更新日時(例:2016-7-18_17:54:00
    • $_current: 変更があったファイルの今回の更新日時(例:2016-7-18_17:54:57

Motivator

きっかけは、Sublimetextでmermaid.jsのシーケンス図をリアルタイムプレビューしたかったことです。Atomだとプラグインがありました。 このプラグインはすこぶるきちんと動作していたのでAtom使えばいいんですが。

ただ、やりたいことは「mermaidファイルの変更を検知してmermaidコマンドを叩きたい」だけなのに、こういう状況が発生する度にエディタにプラグインを書くことにするとしたらちょっと面倒に思えました。 タイトルにもある通りそういう汎用動作がスクリプトであればいいだけなので。*2

実際にSublimeで画面分割して、右ペインに生成されるpngを、左ペインにmermaidのファイルを開いて書いてみて、ややモッサリしているけれど概ねうまく動作してくれています。

f:id:hatappo:20160718184703j:plain

Others

ちなみに、mermaidをサポートしているエディタは、Atom以外にHaroopadgitbookのエディタ があります。

Haroopadは、サポートしているのが次のようなインラインコード形式で書く場合のみで、ファイル全体をmermaidとして扱うことには対応していません。マークダウンエディタなので、そりゃそうです。

```mermaid
.....
```

gitbookのエディタを使ってみようと、プラグインmermaidで検索したら6つくらいヒットしました。どれがいいのかよく分からないので、挫折しました。ごめんなさい。

Impression

  • Shellは書かないとすぐ忘れてしまう。 *$@$*がどっちがどっちだったかとか。*3
  • Shellで配列を久しぶりに使ったんだけど、これってkshとかだと挙動違うからポータビリティ的にアウトだよね。。ごめんなさい。
  • ls -l --full-timeの代わりはbash - issues "using ls -al --full-time" in OSX - Stack Overflowを参考にls -lTを使いました。ただ、このコマンドだとミリ秒を扱えないので、ミリ秒以内の変更は検知できない場合がありますが。

*1:本当は変更があったファイルリストを $_files とかの名前で配列として参照できるほうが正しい気がする。そうすれば第一引数のコマンドの中で、ファイル1つ1つに for で何らかの操作をする書き方もできるし、まとめて一回何かする書き方もできる。

*2:というかスクリプトじゃなくて、そういう汎用的なwatch & execができるエディタ・プラグイン書けば良かったのか、、今更だ。探したらそれはありそうだなー

*3:ダブルクォートで囲ったときの挙動の違い。$@は要素それぞれをクォートして展開する。$*は要素全体を展開した状態でクォートする。