サーバーやRaspberry Piの運用で「毎日決まった時間にスクリプトを動かしたい」となったとき、まず候補になるのがcronです。
ただ、私はcrontabの5つの数字の並びを、恥ずかしながら毎回検索し直していました。
この記事では、crontabの基本書式と、実際にハマりやすい落とし穴を3つに絞って整理します。
crontabの基本書式(5つのフィールド)

crontabは「分 時 日 月 曜日 コマンド」の並びで、1行に1ジョブを書きます。
# 分 時 日 月 曜日 コマンド
*/5 * * * * /home/user/check.sh
0 6 * * 1 /home/user/backup.sh
各フィールドの範囲は、分が0〜59、時が0〜23、日が1〜31、月が1〜12、曜日が0〜6となっています。
曜日は0が日曜日で、1が月曜、6が土曜の並びです。
編集はcrontab -e、登録内容の確認はcrontab -lを使います。
よく使う記法

毎回ゼロから考えなくても、よく使うパターンはだいたい決まっています。
0 9 * * 1-5 # 平日9時
0 9 1,15 * * # 毎月1日と15日の9時
*/10 * * * * # 10分おき
@daily # 毎日0時(0 0 * * * と同じ)
ハイフンは範囲、カンマは列挙、スラッシュは間隔を表します。
@dailyや@rebootのような特殊文字列も使えますが、対応は実装によって差があるため、crontab(5)のmanページで確認しておくと安心です。
落とし穴①:「日」と「曜日」の両方指定はOR判定
「毎月1日が金曜のときだけ」のつもりで日と曜日を両方埋めると、期待と違う動きをします。
両方のフィールドが「*以外」のとき、cronはどちらかが一致した日に実行する仕様だからです。
30 4 1,15 * 5
# 毎月1日・15日の4:30に加えて、毎週金曜の4:30にも実行される
この挙動はmanページにも明記されている公式の仕様で、AND条件にしたい場合はコマンド側で曜日チェックを挟むのが定石になっています。
落とし穴②:cronの環境変数はログインシェルと別物
「手で実行すると動くのに、cronだと動かない」というトラブルの大半はここが原因でした。
cronのジョブはログインシェルを経由せず、PATHがほとんど通っていない最小限の環境で実行されます。
対策はコマンドをフルパスで書くか、crontabの冒頭でSHELLとPATHを宣言しておくことです。
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
0 6 * * * /usr/local/bin/python3 /home/user/job.py >> /home/user/job.log 2>&1
あわせて標準出力とエラーをログに残しておくと、失敗したときの調査が一気に楽になります。
落とし穴③:%はそのまま書けない
コマンド欄の%は、cronでは改行として解釈される仕様です。
date +%Y%m%dのようなコマンドをそのまま書くと、最初の%の手前でコマンドが切れてしまいます。
# NG: %が改行扱いになり失敗する
0 0 * * * tar czf /backup/$(date +%Y%m%d).tar.gz /home/user/data
# OK: バックスラッシュでエスケープする
0 0 * * * tar czf /backup/$(date +\%Y\%m\%d).tar.gz /home/user/data
バックスラッシュを付ければ、文字としての%をそのまま渡せます。
書式の確認にはcrontab.guruが便利
書いた式が意図どおりかどうかは、crontab.guruに貼り付けると一目で確認できます。
実際にジョブが動いたかは、syslogやjournalctlでcronのログを見るのが確実です。
新しいジョブはまず毎分実行(* * * * *)で動作を確かめてから、本番の時刻に直す手順にすると失敗にすぐ気付けます。
最後に
crontabは書式こそ単純ですが、OR判定・環境変数・%変換のあたりは知らないと確実にハマります。
私自身、毎回manを引き直すのをやめたくて、自分用のチートシートとしてこの記事にまとめました。
定期実行つながりでは、Coworkの定時タスクで日次の自動化を組んだ話も書いているので、あわせてどうぞ。
以上です。









コメントを残す