スケジュールタスク:cronとsystemdタイマー
スケジュールタスクの実行方法、手動では動くのにcronでは動かない理由、systemdタイマーに切り替えるべきタイミングを説明します。
更新日 2026年8月23日
バックアップ、証明書の更新、一時ファイルのクリーンアップ、夜間レポート——これらはすべてスケジュールされたタスクです。Linuxでは、これらを解決する方法が2つあります。古典的なcronとsystemdタイマーです。
Cron:クイックスタート
ユーザーのスケジュールは次のように編集します。
crontab -e
crontab -l
行の形式は5つのフィールドとコマンドです。
# min hour day month day-of-week command
0 4 * * * /usr/local/bin/backup.sh
*/15 * * * * /usr/local/bin/check.sh
30 3 * * 0 /usr/bin/systemctl restart myapp
便利なショートカット:@daily、@hourly、@reboot。ジョブがそもそも実行されたかを確認するには:
grep CRON /var/log/syslog | tail -30
journalctl -u cron --since "1 hour ago"
手動ではスクリプトが動くのにcronでは動かない理由
これは最もよくある問題で、原因はほぼ必ず次の3つのうちのどれかです。
環境が異なる。 CronのPATHは最小限で、.bashrcの変数も一切引き継がれません。プログラムには絶対パスを使い、変数はスクリプトの先頭またはcrontabで明示的に設定してください。
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ディレクトリが異なる。 ジョブはユーザーのホームディレクトリで開始されるため、相対パスは別の場所を指してしまいます。常に絶対パスを使用してください。
出力がどこにも行かない。 エラーが発生しても、誰もそれを見ません。ログを書き出しましょう。
0 4 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
もう2つ小さな点があります。cronの行内の%文字は\%とエスケープする必要があり、crontabファイルは改行で終わらなければなりません——そうでないと最後のジョブが無視されます。
ジョブが実行されたことを外部から検証する必要があります。沈黙したcronは成功したcronとまったく同じに見えます。Uptime Kumaでプッシュチェックを設定しましょう。スクリプトが最後にアドレスへpingし、1日間pingがなければアラートを受け取れます。
systemdタイマー
タスクが単一のコマンドより複雑な場合、タイマーのほうが便利です。ジャーナル、依存関係、リソース制限、そして2つのコピーが同時に実行されることへの保護を備えています。
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Run nightly backup
[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true
RandomizedDelaySec=15m
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers
journalctl -u backup.service -n 50
Persistent=trueは、マシンが停止していた場合に逃した実行をキャッチアップします——cronにはこれができません。RandomizedDelaySecは負荷を分散し、十数のタスクが同じ秒に開始しないようにします。
覚えておくべきこと
- マシンの時刻はデフォルトでUTCです。「午前4時」を設定する前に
timedatectlを確認してください。 - 重いタスク(アーカイブ、バックアップ検証)はディスクに負荷がかかります。ディスク速度を参照し、夜間にスケジュールしてください。
- 5分ごとに実行される長時間タスクは、自分自身と重複します。systemdでは
Type=oneshotが役立ち、cronではflockによるロックを使用します。
*/5 * * * * /usr/bin/flock -n /tmp/job.lock /usr/local/bin/job.sh