◆ incrontab
◆ 便利
◆ あまり情報ないけど コマンドにリダイレクトとか書けない 

incrontab

ファイル更新したときに何かしたいなー と思ってググってると incrontab というのがありました
inotify という ファイルの変更を監視して通知してくれるツールがあってそれを使ってるらしいです

今回はそれ使ってみようと思います
ここに書いてる情報は fedora23 の incrontab 0.5.10 で確認してるものです

インストール

sudo dnf install incron

これでインストールできます
incrontab じゃなくて incron です

起動

変更があったかを見張ってくコマンドを実行してくれるデーモンを起動します
sudo systemctl start incrond

起動しておかないと設定だけしても何も起きません

使い方

cron という名前がついてるだけあって crontab と同じような使い方らしいです
といっても 私は crontab はほとんど使ったことないです

時間が来たら実行してくれるのが crontab
ファイルにアクションがあったら実行してくれるのが incrontab
ということです

設定

incrontab -e
で 設定を編集できます

が 私の環境だといきなりエラーでした
エディタが設定されてないことが原因みたいで EDITOR 環境変数を準備します
export EDITOR=nano
vi でも emacs でもなんでもいいです

~/.bashrc などの rc ファイルに書いておくと 次から書かなくていいので楽です

/etc/incron.conf でも設定できるみたいです
こっちのほうが全部のユーザに対して設定できるのでいいのかもしれません


エディタを終了すると設定が更新されます

incrontab -d が必要と書いてるところもありましたがなくていいです
何かの理由があって設定ファイルのリロードしたいときに -d を使います

確認したいときは
incrontab -l

削除したいときは
incrontab -r
です

設定ファイルの書き方

監視するディレクトリかファイル どのイベントを監視するか イベントが起きた時に実行するコマンド の 3 つをスペース区切りで書きます

パス

/ からの絶対パスじゃないとダメです
ディレクトリでも大丈夫です

マスク

イベントを選びます
イベントは基本は inotify と一緒で特殊なものが一部削られてるみたいです
マニュアルにないだけで実はあるのかもですけど

基本なものはこれです
IN_ACCESS
  読み取りアクセスがあったとき
IN_MODIFY
  更新されたとき
IN_ATTRIB
  属性へんこうされたとき(chmod とか)
IN_CLOSE_WRITE
  ファイルに変更があって閉じられたとき
IN_CLOSE_NOWRITE
  ファイルに変更なしで閉じられたとき
IN_OPEN
  ファイルが開かれたとき
IN_MOVED_FROM
  移動されたとき(移動する元の方)
IN_MOVED_TO
  移動されたとき(移動する先の方)
IN_CREATE
  ファイルやディレクトリが作られた時
  監視しているパスにファイルやフォルダ作られたものじゃなくて
監視しているパスのディレクトリの中に作られたとき
IN_DELETE
  消された時
IN_DELETE_SELF
  監視パスのディレクトリ内じゃなくてパスに書かれている物自体が消されたとき
IN_MOVE_SELF
  監視パスのディレクトリ内じゃなくてパスに書かれている物自体に移動された時
  監視パスのファイルをどこかに移動しても発生しない

パスで指定したもの 1 つだけしか監視できないなんて不便なものではないです
パスで指定するのはディレクトリにしておけば その中のファイルやディレクトリへのアクセスも監視できます
IN_CREATE など指定したパスのディレクトリ内でしか使えないのもあります

SELF がついてる 2 つはパスで指定したもの自身に対するイベントだけでディレクトリ内で起きたものは関係ないです
IN_MOVE_SELF は a というファイルが監視パスで指定されていたら
mv a b
だと反応しなくて
mv b a
に反応するようです

IN_DELETE_SELF の方は rm や rmdir でファイルやディレクトリを消してみましたが 発生しなかったです
あと 移動でもファイルシステムを超えると 移動じゃなくて削除された判断になるみたいです

マスクを複数設定するならカンマ区切りです



マスクは複数をまとめたものもあります
IN_ALL_EVENTS
  上であげたやつ全部です
IN_MOVE
  MOVED 2 つです
IN_CLOSE
  WRITE ありなし両方の CLOSE です

incrontab -e で書いたものは確定時に最適化されます
1 つ 1 つ書いていてもまとめることができるなら勝手にまとめられてしまいます
並び順もソートされていて 存在しないものは消されています



特殊なもの
IN_DONT_FOLLOW
  シンボリック辿らない
IN_ONESHOT
  イベントは一回だけ
IN_ONLYDIR
  指定するパスはディレクトリだけ
IN_NO_LOOP
  実行するコマンドの中で発生したイベントは無視する

IN_NO_LOOP は忘れると大変なことになりそうなので覚えておいたほうがよさそうです

ファイルにアクセスがあったら起きるイベントで実行するコマンドで そのファイル自体にアクセスしたらまたそこでイベントが発生して……と無限ループになるのでそれを防いでくれるみたいです

コマンド

実行するファイル名と引数をかけます
設定ファイルに書く 3 つの内の最後なのでスペースを使えます

注意するところは 監視するパスと一緒で 絶対パスじゃないといけないところです
カレントディレクトリを表示してみたら / だったので ルートディレクトリからの相対パスでも行けそうですが / の有り無し程度ですし 今後変わらないとも言えないので ちゃんと絶対パスにしておくのが安全そうです

パスが通ってないので sh とか node とか直接書くことができないです
/home/user/aaa.sh IN_CLOSE /bin/sh /home/user/aaa.sh
みたいに書かないとダメです
シェバン書いてるなら /bin/sh 入らないですが それでも aaa.sh の方は絶対パスで書かないとダメです

nodebrew で入れてる node を実行しようとしたらちょっと長くて大変です
/home/user/xxx.js IN_CLOSE_WRITE /home/user/.nodebrew/node/v5.5.0/bin/node /home/user/xxx.js



それともうひとつ リダイレクト などは使えず コマンドの実行だけにしないとダメです
/tmp/test IN_MODIFY,IN_CREATE echo 1 > /tmp/1
これは動かないです

正確には echo 1 のコマンド部分は実行されてますが リダイレクト部分が実行されず 出力されません

リダイレクトしたい場合は incrontab の設定は sh ファイルにしておいて sh ファイルの中で リダイレクトすればできます
/tmp/test IN_MODIFY,IN_CREATE /tmp/testecho.sh
[/tmp/testecho.sh]
echo 1 > /tmp/1



ディレクトリ内のどれかに対してのアクションでもイベントは発生します
そのときに どのファイルにアクセスがあったかを知る方法があります
$@
  監視しているパスです
  監視するパスを複数設定してるときやディレクトリ内のイベントのときに使えます

$#
  イベントが発生したファイルまたはディレクトリの監視しているパスからの相対パスです
  監視しているパス自体でイベントが起きたら空文字です

$%
  どのイベントが起きたかです
  IN_CREATE みたいな文字が入ります

$&
  どのイベントが起きたかです
  こっちは数字が入ります

$$
  $ から始まると特殊な扱いになるので $$ で $ を表します

$& の数字はこういう対応です

IN_ACCESS1
IN_MODIFY2
IN_ATTRIB4
IN_CLOSE_WRITE8
IN_CLOSE_NOWRITE16
IN_OPEN32
IN_MOVED_FROM64
IN_MOVED_TO128
IN_CREATE256
IN_DELETE512
IN_DELETE_SELF1024
IN_MOVE_SELF2048

サンプル

使ってみた例です
こんな感じです

systemctl start incrond

cd ~
mkdir test
touch test/a
cd ~
touch args

cat <<EOF > print_args.php
<?php
file_put_contents("/home/user/args", join(",", \$argv));
EOF

incontab -e
==
/home/user/test/a IN_MODIFY /bin/php /home/user/print_args.php $@ $# $% $&
==

echo xxx > test/a
cat args
==
/home/user/print_args.php,/home/user/test/a,,IN_MODIFY,2
==

incontab -e
==
/home/user/test IN_MODIFY /bin/php /home/user/print_args.php $@ $# $% $&
==

echo xxx > test/a
cat args
==
/home/user/print_args.php,/home/user/test/,a,IN_MODIFY,2
==

ファイルの場所

コマンドを設定したファイルの場所

incrontab -e で編集しているファイルは

/var/spool/

以下にあります

incrontab -e を実行したユーザとしてコマンドが実行されます
なので incrontab -e を実行したユーザ名で /var/spool/ 以下に保存されています

たぶん直接こっちを書き換えたりすると incrontab -d のリロードがいるんだと思います

 ログ

ログは cron と同じで

/var/log/cron

に保存されます

ですが このファイルが存在しない場合は 別のところ

/var/log/messages

になります
ただ fedora23 ではこのファイルがなくて

journalctl

で見れるログに書き込まれていました

まとめ

これがあるとファイル上書きしたら自動実行させるということができそうです