crontab は、指定したスケジュールでコマンドを自動実行してくれる便利な仕組みです。
設定は次の5フィールドで書きます。
分 時 日 月 曜日 コマンド
たとえば、
0 2 10 * * bash /path/to/foo.sh
これは「毎月10日の午前2:00に bash /path/to/foo.sh を実行する」という意味になります。
同じく、
0 2 * * 3 bash /path/to/foo.sh
は「毎週水曜日の午前2:00に実行」です。
(曜日は 0〜7 が日曜、3 が水曜)
「日」と「曜日」を両方指定するとどうなるか?
ここが落とし穴なのですが、「日(day-of-month)」と「曜日(day-of-week)」を両方 * 以外で指定した場合、cron は AND ではなく OR で判定します。
つまり、
0 2 10 * 3 bash /path/to/foo.sh
これは直感的には
「水曜日 かつ 10日の午前2:00に実行」
と思いがちです。
でも実際は違って、
「水曜日の午前2:00」
または
「毎月10日の午前2:00」
の どちらかにマッチしたら実行されます。
これを知らなかった頃の失敗談
昔、特定の日時に夜間1回だけ実行したいプログラムがありました。
実現するためにどうするか、ですが、「一回きりの日時指定ツール」もあるのですが、使い慣れていなくて設定ミスで動かないのがいやだったんですよね。
なので、慣れている crontab にしました。
「12月10日の午前2:00に1回実行したい」なら、こうです。
0 2 10 12 * bash /path/to/foo.sh
ただ、これだと実行後に削除しないと翌年も動いてしまう。
「削除し忘れたらイヤだな……」と考えて、
12月10日が同じ曜日になるのは数年先のはず
曜日も指定しておけば、少しは安全だろう。。
と、軽い気持ちで曜日に水曜(3)をつけました。
0 2 10 12 3 bash /path/to/foo.sh
ところが、12月10日を迎える前のある水曜日に、
「何か変だけど調べて」
と言われてログを見ると、
12月10日にしか動かないはずのプログラムが午前2:00に実行されている。。。
なんでやねん!と設定を見直しても間違いはないように見える。
でも、念のため cron の仕様をよく調べると…
冒頭のとおり、日と曜日は OR 条件でした。
この設定はつまり、
12月10日の午前2:00
OR
12月の毎週水曜日の午前2:00
に実行される、という意味だったわけです。
ですので実行されてはいけない12月3日(水)の午前2:00に実行されてしまったのですね。
まとめ
cron の「日」と「曜日」を両方指定すると OR 判定になる
「その日がその曜日のときだけ」という絞り込みには使えない
気をつけましょう。

