🐧 Linux 総合学習プラットフォーム
自動化/定期実行 ・ 中級〜上級

変化を見張って動かす(inotifywait・systemd path)

定期実行は「時間が来たら動く」仕組みですが、世の中には「置かれた瞬間に処理したい」場面があります。1分ごとに見に行く cron では、最悪1分遅れます。そこで使うのが inotify、Linux カーネルが持つファイル監視の機構です。この回では inotifywait でファイルの出現を待ち受けるループの作り方と、同じことをサービスとして常駐させる systemd の path unit を学びます。何度も見に行くポーリングとの違いも押さえます。

cron や systemd timer は「時間が来たら動く」仕組みだ。多くの用途はこれで足りる。だが世の中には、時刻ではなく出来事に反応したい場面がある。「ファイルが置かれた、その瞬間に処理したい」というときだ。

たとえば、あるフォルダに画像が投げ込まれたら即座に変換したい。1分ごとに見に行く cron でも一応できるが、運が悪ければ最大1分待たされるし、何も来ない59分もフォルダを覗き続けることになる。無駄が多く、反応も鈍い。

🔗
たとえポーリング(定期的に見に行く方式)は、宅配が来たか5分おきに玄関を開けて確かめる人だ。対して監視方式は、呼び鈴を付けて座って待つ人。鳴った瞬間に動けるし、それまでは他のことをしていられる。
💡
ポイント「時間で動く」定期実行に対して、「出来事で動く」のが監視だ。置かれた瞬間に反応したいなら、時刻ではなく変化そのものを引き金にする。

🔔 カーネルが持つ監視機構 inotify

Linux には、ファイルの変化を見張るための仕組みがカーネルの中に用意されている。それが inotify(アイノーティファイ)だ。ファイルやフォルダに対する「作られた・書かれた・消された」といった出来事を、カーネルが検知して教えてくれる。

ここが肝心なのだが、inotify は自分でぐるぐる見に行くのではない。カーネルに「このフォルダを見張っておいて、何か起きたら起こして」と頼み、あとは眠って待つ。だから CPU をほとんど使わずに、変化の瞬間に反応できる。

ポーリング(見に行く)1分ごと確認フォルダ空振りが多い・最大1分遅れinotify(待ち受ける)眠って待つフォルダ置かれた瞬間に通知CPU をほぼ使わず即反応

⏳ inotifywait で待ち受ける

この inotify をコマンドラインから使えるようにしたのが inotifywait だ。監視したい場所と、拾いたい出来事の種類を渡すと、その出来事が起きるまでそこで待ち、起きたら一言返して終わる。

よく使うオプションは2つ。-e は拾う出来事の種類を指定する(create=作成、modify=変更、delete=削除など)。-m は monitor(モニター)モードで、1回で終わらず出来事のたびに何度でも報告し続ける。

あるフォルダにファイルが作られたら、その名前を受け取って処理するループ。 $ inotifywait -m -e create /var/spool/incoming | while read dir event file; do echo "来た: $file" process.sh "$dir$file" done

-m で報告が流れ続け、while read でその1件ずつを受け取る。ファイルが置かれるたびに $file にその名前が入り、すぐ process.sh に渡せる。cron のような待ち時間はなく、置かれた瞬間に動く。

💡
ポイントinotifywait -m -e create + while read が、いちばん素直な待ち受けループの型だ。「何を・どの出来事で監視するか」だけ決めれば動く。
つまずきinotifywait は多くのディストリで inotify-tools というパッケージに入っている。標準では未導入のことがあるので、無ければパッケージ管理ツールで入れてから使う。
つまずきファイルのコピー中にも create は発火しうる。大きなファイルだと、まだ書き終わっていない途中で拾ってしまうことがある。そういう時は close_write(書き込みを閉じた)という出来事を狙うと、完成後に反応できる。

🛎️ サービスにするなら systemd path unit

手元のループは分かりやすいが、サーバーで常駐させるなら、端末を閉じたら止まってしまう while ループより、systemd に任せたほうが堅い。そのための仕組みが path unit(パスユニット)だ。

path unit は「指定した場所にファイルが現れたら、対応するサービスを起動する」という監視係を、systemd の一員として動かす。中身はやはり inotify なので、ポーリングではなく変化の瞬間に反応する。

watch.path と watch.service の2枚を組にする。フォルダにファイルが現れたらサービスが起きる。 $ cat /etc/systemd/system/watch.path [Path] PathExistsGlob=/var/spool/incoming/* [Install] WantedBy=multi-user.target

PathExistsGlob は「この形のファイルが存在したら」という条件だ。相方の watch.service に実際の処理を書いておけば、条件が満たされた瞬間に systemd がそれを起動する。あとは systemctl enable --now watch.path で見張りが常駐する。

フォルダに出現*.datwatch.path出現を見張るwatch.service処理が起動systemd が常駐して見張る
🔗
たとえwhile ループの見張りは「自分で立って番をする人」、systemd path unit は「番を組織に任せる」ようなものだ。人が離席しても、電源を入れ直しても、組織のほうが勝手に持ち場へ戻ってくれる。

⚖️ ポーリングとの違いを押さえる

ここまでの主役はどれも、見に行くポーリングではなく、変化を通知してもらう監視だった。両者は結果が似て見えても、性質が違う。ポーリングは間隔ぶんだけ遅れ、空振りぶんだけ資源を使う。監視は即応で、待つ間は静かだ。

つまずきただし監視が万能なわけではない。監視できるのは基本的にローカルのファイルシステムで、ネットワーク越しの共有フォルダなどでは inotify が変化を拾えないことがある。その場合は、割り切ってポーリングを選ぶ判断も要る。
💡
ポイント「決まった時刻でよい」なら timer、「起きたら即」ならファイル監視。遅延の許容度と反応の速さで、どちらの引き金にするかを選ぶ。

定期実行では届かなかった「その瞬間」に、これで手が届くようになった。inotifywait で待ち受け、常駐させたいなら systemd の path unit に任せる。時間で動く自動化と、出来事で動く自動化。この2枚のカードを場面で使い分けられれば、自動化の幅はぐっと広がる。

この項目に出てくる用語

inotifyあいのーてぃふぁい
Linux カーネルが持つ、ファイルやフォルダの変化を検知する監視機構。
path unitぱすゆにっと
指定した場所にファイルが現れたら対応サービスを起動する systemd のユニット。
ポーリングぽーりんぐ
一定間隔で繰り返し状態を見に行き、変化がないか確かめる方式。

関連コマンド

inotifywait

▶ 学習アプリでこの続きを学ぶ・演習する