crontab の書式(5フィールド)
crontab の1行は「分 時 日 月 曜日 コマンド」の順で書きます。先頭の5つが実行タイミングを表すフィールドで、それぞれ分(0-59)・時(0-23)・日(1-31)・月(1-12)・曜日(0-7、0と7が日曜)です。アスタリスク * は「毎」を意味し、*/5 は「5ごと」、1,15 は「列挙」、1-5 は「範囲」を表します。例えば 0 3 * * * は毎日午前3時0分、*/10 * * * * は10分おきの実行になります。
crontab に書く1行を正しく読み書きできれば、定期実行のタイミング設計はほぼ手中に収まる。まずはその1行の形を見ていこう。
crontab の各行は、先頭から「分・時・日・月・曜日」の5つのフィールドと、それに続く「実行するコマンド」で構成される。区切りの空白で6つの部分に分かれ、最初の5つが「いつ動かすか」を、6つ目以降が「何を動かすか」を表す。
たとえば 0 3 * * * /usr/local/bin/backup.sh という1行を見てみよう。左の5フィールドが「毎日午前3時0分」というタイミングを表し、右の部分が「そのときに backup.sh を実行する」ことを表す。
この5フィールド方式(cron式)が読み書きできるようになると、タイミング設計はほぼここで完結する。逆にここがあいまいだと、狙った時刻と実際の実行がずれて悩むことになる。最初にしっかり固めておきたい土台だ。
実際、よくある悩みがこれだ。「毎日午前3時に動かしたいだけ」なのに、なぜか毎時3分に動いてしまう。原因は書式の読み違いにある。
🔢 5つのフィールドが取れる値
5つのフィールドが受け付ける値の範囲は決まっている。第1フィールドは分で 0 から 59。第2フィールドは時で 0 から 23(24時間制)。第3フィールドは日で 1 から 31。第4フィールドは月で 1 から 12。第5フィールドは曜日で 0 から 7 だ。
曜日は少し特殊だ。0 と 7 のどちらも日曜を表し、1が月曜、2が火曜、…、6が土曜となる。
月や曜日は jan・feb… や sun・mon… といった英語の3文字略称でも書けるが、数字で統一しておくほうが読み違いが減る。
順番を「分・時・日・月・曜日」と暗記しておくことが、書き間違いを防ぐ第一歩だ。とくに先頭が「時」ではなく「分」から始まる点に注意したい。
ここを取り違えると、たとえば「3時に動かすつもり」が「毎時3分に動く」ことになり、時刻がまるごとずれてしまう。冒頭の悩みの正体がこれである。
慣れるまでは、書いた式を左から「分が…、時が…」と声に出して読み返す癖をつけると安全だ。
✳ 数字以外の書き方
各フィールドには、単なる数字以外にいくつかの記法が使える。
まず * (アスタリスク)は「そのフィールドのすべての値」、平たく言えば「毎」を意味する。* * * * * は「毎分」だ。
次に - を使った範囲指定がある。たとえば時フィールドの 9-17 は「9時から17時まで」を表す。
, を使えば列挙できる。分フィールドの 0,30 は「0分と30分」、つまり毎時0分と30分の2回だ。
そして / を使った刻み(ステップ)指定が便利だ。*/5 は「5おきに」を意味する。分フィールドの */5 なら5分おき、*/10 なら10分おきだ。
範囲と刻みは 0-30/10 のように組み合わせることもできる。これは「0分から30分の間で10分おき(0分・10分・20分・30分)」を表す。
これらを複数フィールドにまたがって使えば、細かいスケジュールも書ける。たとえば「平日の9時から18時まで30分おき」なら 0,30 9-18 * * 1-5 と表現できる。
🔊 具体例を左から声に出して読む
代表的な例を、左から順に声に出して読む練習をしておくと身につく。
0 3 * * * は「分が0、時が3、日・月・曜日は毎」なので毎日午前3時0分。
*/10 * * * * は「10分おき、時・日・月・曜日は毎」なので10分おきにずっと。
30 2 * * 0 は「2時30分、曜日が0=日曜」なので毎週日曜の午前2時30分。
0 9 1 * * は「9時0分、日が1」なので毎月1日の午前9時。
0 0 * * 1-5 は「0時0分、曜日が1-5=月〜金」なので平日の毎晩深夜0時。
45 23 * * 6 なら毎週土曜の23時45分、0 */6 * * * なら6時間おき(0時・6時・12時・18時)になる。
読むときは必ず左端の分から順にたどるのがコツだ。これに慣れると、初めて見る式でもその場で意味を解釈できるようになる。
書いた後は crontab -l で登録内容を見直し、date で現在時刻を確かめる。最初はわざと短い間隔でテストして動作を確認してから、本番の間隔に直すと失敗が減る。
🤔 いちばん誤解される、日と曜日の関係
ここまで読めるようになっても、最後に待ち構える罠がある。crontab の書式で最も誤解されやすいのが、第3フィールド(日)と第5フィールド(曜日)の関係だ。
直感では「日と曜日の両方を満たしたときだけ実行」と思いがちだ。だが cron の仕様は違う。日と曜日の双方が * 以外で指定されている場合、どちらか一方が一致すれば実行される(AND ではなく OR 条件)。
たとえば 0 0 13 * 5 は「毎月13日」または「毎週金曜」のどちらかに当てはまる日すべてに動く。「13日の金曜だけ」にはならない。意図せず想定の何倍も動いてしまう、よくある事故の元だ。
13日の金曜だけを狙うようなケースは、素の cron では正しく書けない。毎週金曜に起動したうえで、スクリプト側で if [ \"$(date +%d)\" = \"13\" ] のように日付を確認して処理を分岐する、といった工夫が必要になる。
逆に、日と曜日のどちらかを * にしておけば、この OR の罠にはかからない。
⚠ もう1つの罠 — % を含むコマンド
もう1つの定番のはまりどころが % 記号だ。crontab のコマンド部分では、エスケープしない % が「改行」として特別扱いされる。最初の % より前がコマンド、後ろがそのコマンドへの標準入力として渡される。
そのため date +%Y%m%d のように % を含むコマンドをそのまま書くと意図どおり動かない。
回避するには、バックスラッシュで \% とエスケープするか、処理をスクリプトファイルにまとめてそのスクリプトを呼ぶ形にする。
実務では後者が定番だ。複雑な処理や % を含む処理はスクリプト化し、crontab からは 0 3 * * * /usr/local/bin/backup.sh のように絶対パスで1行呼ぶだけ、という形がいちばん安全で読みやすい。
書式そのものはこの項で押さえたとおりだ。これに「凝ったことは1行に詰め込まずスクリプトへ」という方針を併せて持っておくと、cron まわりのトラブルの多くを未然に防げる。つまずいたら、まずその1行が長すぎないか、% を裸で書いていないかを見直すとよい。