Cron Jobs and Task Scheduling
Cron ジョブとタスクスケジューリング 完全ガイド
目次
- はじめに
- cron の基礎
- 2.1 cron とは
- 2.2 cron デーモンの仕組み
- 2.3 crontab の構文
- 2.4 特殊文字列
- ユーザー crontab の管理
- 3.1 crontab コマンド
- 3.2 crontab の編集と確認
- 3.3 実践的な設定例
- システム crontab
- 4.1 /etc/crontab
- 4.2 /etc/cron.d/ ディレクトリ
- 4.3 定期実行ディレクトリ
- cron のアクセス制御
- 5.1 cron.allow と cron.deny
- 5.2 アクセス制御の優先順位
- anacron:非24時間稼働システム向けスケジューラ
- 6.1 anacron の概要
- 6.2 anacrontab の設定
- 6.3 cron と anacron の連携
- at コマンドと batch コマンド
- 7.1 at コマンド
- 7.2 batch コマンド
- 7.3 atq と atrm
- systemd タイマー
- 8.1 systemd タイマーの概要
- 8.2 タイマーユニットの作成
- 8.3 OnCalendar による時刻指定
- 8.4 OnBootSec / OnUnitActiveSec
- 8.5 Persistent オプション
- 8.6 一時的タイマー (systemd-run)
- cron vs systemd タイマー比較
- cron ジョブのログとモニタリング
- cron のエラーハンドリング
- cron の環境変数
- 12.1 デフォルト環境変数
- 12.2 環境変数の設定方法
- 12.3 PATH の取り扱い
- ベストプラクティス
- よくある落とし穴と対策
- トラブルシューティング
- 参考文献
1. はじめに
Linux システム管理において、定期的なタスクの自動実行は最も重要な運用業務の一つである。バックアップ、ログローテーション、システム監視、レポート生成など、日常的に繰り返されるタスクを手動で実行することは非効率であり、人的ミスの原因ともなる。
本ドキュメントでは、Linux におけるタスクスケジューリングの主要な仕組みである cron、anacron、at/batch、および systemd タイマーについて、基礎から実践的な運用ノウハウまでを網羅的に解説する。
2. cron の基礎
2.1 cron とは
cron は UNIX/Linux システムにおいて、指定した時刻・間隔でコマンドやスクリプトを自動的に実行するデーモンプロセスである。名前はギリシャ語の「chronos(時間)」に由来する。
主要な cron 実装として以下がある。
| 実装 | 特徴 | 代表的なディストリビューション |
|---|---|---|
| Vixie cron | 伝統的な cron 実装 | Debian/Ubuntu (従来) |
| cronie | Red Hat が開発・保守 | RHEL, CentOS, Fedora, Rocky Linux |
| busybox cron | 軽量な組み込み向け | Alpine Linux |
| systemd-cron | systemd タイマーへの橋渡し | Arch Linux (オプション) |
2.2 cron デーモンの仕組み
cron デーモン (crond) は以下の手順で動作する。
- デーモン起動時に全ての crontab を読み込む
- 毎分、実行すべきジョブがあるかチェック
- 該当するジョブがあれば、子プロセスとして実行
- crontab ファイルの変更を検知し、自動的にリロード
# cron デーモンの状態確認
$ systemctl status crond # RHEL系
$ systemctl status cron # Debian系
# 出力例
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2026-04-06 09:00:00 JST; 4 days ago
Main PID: 1234 (crond)
Tasks: 1 (limit: 49152)
Memory: 2.4M
CGroup: /system.slice/crond.service
└─1234 /usr/sbin/crond -n
2.3 crontab の構文
crontab の各行は、5つの時間フィールドと実行コマンドで構成される。
┌───────────── 分 (0 - 59)
│ ┌───────────── 時 (0 - 23)
│ │ ┌───────────── 日 (1 - 31)
│ │ │ ┌───────────── 月 (1 - 12)
│ │ │ │ ┌───────────── 曜日 (0 - 7, 0と7は日曜日)
│ │ │ │ │
│ │ │ │ │
* * * * * コマンド
各フィールドで使用可能な表記法:
| 表記 | 意味 | 例 |
|---|---|---|
* | 全ての値 | * * * * * (毎分) |
, | 複数の値のリスト | 1,15,30 * * * * (1分、15分、30分) |
- | 範囲指定 | 1-5 * * * * (1〜5分) |
/ | ステップ値 | */10 * * * * (10分ごと) |
L | 月の最終日 (一部実装) | 0 0 L * * (月末) |
具体的な設定例:
# 毎日午前3時に実行
0 3 * * * /usr/local/bin/backup.sh
# 平日の午前9時から午後6時まで30分ごとに実行
*/30 9-18 * * 1-5 /usr/local/bin/health_check.sh
# 毎月1日と15日の午前0時に実行
0 0 1,15 * * /usr/local/bin/report.sh
# 毎週日曜日の午前2時に実行
0 2 * * 0 /usr/local/bin/weekly_maintenance.sh
# 1月から3月の毎日午前6時に実行
0 6 * 1-3 * /usr/local/bin/quarterly_task.sh
# 2時間ごとに実行
0 */2 * * * /usr/local/bin/monitoring.sh
2.4 特殊文字列
cron は頻繁に使用されるスケジュールパターンに対して、特殊文字列(ショートカット)を提供する。
| 文字列 | 意味 | 等価な表現 |
|---|---|---|
@reboot | システム起動時 | なし(特殊) |
@yearly / @annually | 年に1回(1月1日 0:00) | 0 0 1 1 * |
@monthly | 月に1回(毎月1日 0:00) | 0 0 1 * * |
@weekly | 週に1回(日曜日 0:00) | 0 0 * * 0 |
@daily / @midnight | 毎日0:00 | 0 0 * * * |
@hourly | 毎時0分 | 0 * * * * |
# 使用例
@reboot /usr/local/bin/startup_script.sh
@daily /usr/local/bin/daily_backup.sh
@weekly /usr/local/bin/weekly_report.sh
3. ユーザー crontab の管理
3.1 crontab コマンド
ユーザー crontab は crontab コマンドを使用して管理する。
# 現在のユーザーの crontab を表示
$ crontab -l
# crontab を編集(EDITOR 環境変数で指定されたエディタを使用)
$ crontab -e
# crontab を削除(確認なしで全削除されるため注意)
$ crontab -r
# 削除前に確認プロンプトを表示(-i オプション、cronie のみ)
$ crontab -ri
# 特定ユーザーの crontab を表示(root 権限が必要)
$ sudo crontab -u username -l
# ファイルから crontab をインポート
$ crontab mycrontab.txt
# crontab を標準入力から設定
$ echo "0 3 * * * /usr/local/bin/backup.sh" | crontab -
3.2 crontab の編集と確認
# EDITOR を vim に設定して crontab を編集
$ EDITOR=vim crontab -e
# 現在の crontab をファイルにバックアップ
$ crontab -l > ~/crontab_backup_$(date +%Y%m%d).txt
# バックアップから復元
$ crontab ~/crontab_backup_20260410.txt
# 全ユーザーの crontab を一括確認(root 権限)
$ for user in $(cut -f1 -d: /etc/passwd); do
echo "=== $user ==="
crontab -u $user -l 2>/dev/null
done
3.3 実践的な設定例
# ユーザー crontab の全体例
# --- 環境変数の設定 ---
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=admin@example.com
# --- バックアップジョブ ---
# データベースバックアップ(毎日午前2時)
0 2 * * * /home/user/scripts/db_backup.sh >> /var/log/db_backup.log 2>&1
# ファイルバックアップ(毎日午前3時)
0 3 * * * /home/user/scripts/file_backup.sh >> /var/log/file_backup.log 2>&1
# --- 監視ジョブ ---
# ディスク使用率チェック(毎時)
0 * * * * /home/user/scripts/disk_check.sh
# サービス稼働確認(5分ごと)
*/5 * * * * /home/user/scripts/service_monitor.sh > /dev/null 2>&1
# --- レポートジョブ ---
# 日次レポート(毎日午前7時)
0 7 * * * /home/user/scripts/daily_report.sh
# 週次レポート(月曜午前8時)
0 8 * * 1 /home/user/scripts/weekly_report.sh
4. システム crontab
4.1 /etc/crontab
システム crontab は /etc/crontab に格納され、ユーザー crontab とは異なり、実行ユーザーフィールドが追加される。
$ cat /etc/crontab
# /etc/crontab: system-wide crontab
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# 分 時 日 月 曜日 ユーザー コマンド
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
重要な注意点:
/etc/crontabは直接エディタで編集する(crontab -eは使用しない)- ユーザーフィールド(6番目)が必須
- このファイルの変更は cron デーモンが自動検知する
4.2 /etc/cron.d/ ディレクトリ
/etc/cron.d/ ディレクトリには、パッケージやアプリケーションが独自のスケジュールを配置できる。
$ ls -la /etc/cron.d/
total 24
drwxr-xr-x 2 root root 4096 Apr 1 00:00 .
drwxr-xr-x 90 root root 4096 Apr 10 09:00 ..
-rw-r--r-- 1 root root 201 Jan 15 12:00 sysstat
-rw-r--r-- 1 root root 102 Feb 1 00:00 logrotate-custom
-rw-r--r-- 1 root root 189 Mar 10 00:00 certbot
# /etc/cron.d/sysstat の例
$ cat /etc/cron.d/sysstat
# Activity reports every 10 minutes
*/10 * * * * root /usr/lib64/sa/sa1 1 1
# Summary report at 23:53
53 23 * * * root /usr/lib64/sa/sa2 -A
# /etc/cron.d/certbot の例
$ cat /etc/cron.d/certbot
# Let's Encrypt certificate renewal
0 */12 * * * root certbot renew --quiet --post-hook "systemctl reload nginx"
ファイルの命名規則:
- ファイル名にドット(
.)やチルダ(~)を含めてはいけない(無視される) - ファイルのパーミッションは
644(root 所有) が推奨 - 構文は
/etc/crontabと同じ(ユーザーフィールドが必要)
4.3 定期実行ディレクトリ
# 各ディレクトリの役割
/etc/cron.hourly/ # 毎時実行されるスクリプト
/etc/cron.daily/ # 毎日実行されるスクリプト
/etc/cron.weekly/ # 毎週実行されるスクリプト
/etc/cron.monthly/ # 毎月実行されるスクリプト
# ディレクトリ内のスクリプト例
$ ls -la /etc/cron.daily/
total 48
drwxr-xr-x 2 root root 4096 Apr 1 00:00 .
drwxr-xr-x 90 root root 4096 Apr 10 09:00 ..
-rwxr-xr-x 1 root root 376 Jan 15 00:00 apport
-rwxr-xr-x 1 root root 1478 Mar 20 00:00 apt-compat
-rwxr-xr-x 1 root root 355 Feb 1 00:00 bsdmainutils
-rwxr-xr-x 1 root root 384 Jan 10 00:00 cracklib-runtime
-rwxr-xr-x 1 root root 1187 Mar 5 00:00 dpkg
-rwxr-xr-x 1 root root 372 Jan 20 00:00 logrotate
-rwxr-xr-x 1 root root 1123 Feb 15 00:00 man-db
スクリプトの要件:
- 実行権限 (
chmod +x) が必要 - ファイル名にドットを含めてはいけない(
script.shは不可、scriptとする) run-partsコマンドによって実行される
# run-parts の動作確認(ドライラン)
$ run-parts --test /etc/cron.daily/
/etc/cron.daily/apport
/etc/cron.daily/apt-compat
/etc/cron.daily/logrotate
/etc/cron.daily/man-db
# カスタムスクリプトの配置例
$ sudo cat > /etc/cron.daily/custom-cleanup << 'EOF'
#!/bin/bash
# 30日以上前の一時ファイルを削除
find /tmp -type f -mtime +30 -delete
find /var/tmp -type f -mtime +30 -delete
logger "Custom cleanup completed"
EOF
$ sudo chmod +x /etc/cron.daily/custom-cleanup
5. cron のアクセス制御
5.1 cron.allow と cron.deny
cron の利用を制限するために、2つのファイルが用意されている。
/etc/cron.allow # このファイルに記載されたユーザーのみ cron を使用可能
/etc/cron.deny # このファイルに記載されたユーザーは cron を使用不可
5.2 アクセス制御の優先順位
アクセス制御は以下の優先順位で判定される。
1. /etc/cron.allow が存在する場合:
→ ファイルに記載されたユーザーのみ使用可能
→ それ以外のユーザーは全て拒否(root を除く)
2. /etc/cron.allow が存在せず、/etc/cron.deny が存在する場合:
→ ファイルに記載されたユーザーのみ拒否
→ それ以外のユーザーは全て許可
3. どちらのファイルも存在しない場合:
→ ディストリビューションにより異なる
→ RHEL系: root のみ使用可能
→ Debian系: 全ユーザーが使用可能
# cron.allow の設定例(特定ユーザーのみ許可)
$ sudo cat > /etc/cron.allow << 'EOF'
root
admin
deploy
monitoring
EOF
# cron.deny の設定例(特定ユーザーのみ拒否)
$ sudo cat > /etc/cron.deny << 'EOF'
guest
testuser
EOF
# アクセス拒否時のエラーメッセージ
$ crontab -e
You (username) are not allowed to use this program (crontab)
See crontab(1) for more information
6. anacron:非24時間稼働システム向けスケジューラ
6.1 anacron の概要
anacron は、常時稼働していないシステム(デスクトップ PC やノートパソコン)向けのタスクスケジューラである。cron はシステムが停止中のタスクをスキップするが、anacron はシステム起動時に未実行のタスクを検出し、実行する。
cron と anacron の比較:
| 項目 | cron | anacron |
|---|---|---|
| 最小実行間隔 | 1分 | 1日 |
| デーモンとして動作 | はい | いいえ(実行後終了) |
| 正確な時刻指定 | はい | いいえ |
| 未実行ジョブの検出 | なし | あり |
| ユーザー別設定 | あり | なし(root のみ) |
6.2 anacrontab の設定
$ cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# ランダムな遅延の最大値(分)
RANDOM_DELAY=45
# ジョブ実行開始の最早時刻
START_HOURS_RANGE=3-22
# 期間(日) 遅延(分) ジョブID コマンド
1 5 cron.daily nice run-parts /etc/cron.daily
7 25 cron.weekly nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly
各フィールドの意味:
| フィールド | 説明 |
|---|---|
| 期間 | ジョブの実行間隔(日数)。@monthly は特殊値 |
| 遅延 | ジョブ開始前の遅延時間(分)。RANDOM_DELAY が加算される |
| ジョブID | ジョブの識別子。/var/spool/anacron/ にタイムスタンプファイルとして使用 |
| コマンド | 実行するコマンド |
# anacron のタイムスタンプ確認
$ ls -la /var/spool/anacron/
total 24
drwxr-xr-x 2 root root 4096 Apr 10 03:15 .
drwxr-xr-x 7 root root 4096 Jan 1 00:00 ..
-rw------- 1 root root 9 Apr 10 03:15 cron.daily
-rw------- 1 root root 9 Apr 7 03:25 cron.weekly
-rw------- 1 root root 9 Apr 1 03:45 cron.monthly
$ cat /var/spool/anacron/cron.daily
20260410
6.3 cron と anacron の連携
多くのディストリビューションでは、/etc/crontab から anacron が呼び出される仕組みになっている。
# /etc/crontab の典型的な設定
# anacron がインストールされている場合、run-parts は anacron に委譲される
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
この設定は以下のように動作する:
- anacron がインストールされている場合 → anacron が日次タスクを管理
- anacron がない場合 → cron が直接
run-partsを実行
7. at コマンドと batch コマンド
7.1 at コマンド
at コマンドは、一度だけ実行するタスクをスケジュールするために使用する。
# at のインストール
$ sudo dnf install at # RHEL系
$ sudo apt install at # Debian系
# atd デーモンの起動
$ sudo systemctl enable --now atd
# 基本的な使用方法
$ at 15:00
at> /usr/local/bin/send_report.sh
at>
job 1 at Fri Apr 10 15:00:00 2026
# 日時指定のバリエーション
$ at 3:00 PM # 午後3時
$ at 15:00 April 15 # 4月15日 15:00
$ at now + 2 hours # 2時間後
$ at now + 30 minutes # 30分後
$ at now + 1 day # 1日後
$ at midnight # 真夜中
$ at noon # 正午
$ at teatime # 午後4時
# スクリプトファイルからジョブを投入
$ at 03:00 -f /home/user/scripts/maintenance.sh
# パイプからジョブを投入
$ echo "/usr/local/bin/cleanup.sh" | at now + 1 hour
7.2 batch コマンド
batch コマンドは、システム負荷が低い時にジョブを実行する。デフォルトではロードアベレージが 1.5 以下の時に実行される。
# batch の使用
$ batch
at> /usr/local/bin/heavy_processing.sh
at>
job 2 at Fri Apr 10 10:30:00 2026
# ロードアベレージの閾値を変更(atd の起動オプション)
# /etc/sysconfig/atd または /etc/default/atd
OPTS="-l 0.8" # ロードアベレージ 0.8 以下で実行
7.3 atq と atrm
# ジョブキューの確認
$ atq
1 Fri Apr 10 15:00:00 2026 a user
2 Fri Apr 10 10:30:00 2026 b user
3 Sat Apr 11 03:00:00 2026 a user
# 特定ジョブの内容確認
$ at -c 1
#!/bin/sh
# atrun uid=1000 gid=1000
# ...(環境変数のダンプ)
/usr/local/bin/send_report.sh
# ジョブの削除
$ atrm 2
# または
$ at -d 2
# at のアクセス制御
# /etc/at.allow と /etc/at.deny で cron と同様に制御可能
8. systemd タイマー
8.1 systemd タイマーの概要
systemd タイマーは、cron の代替として systemd が提供するタスクスケジューリング機能である。各タイマーは対応するサービスユニットとペアで動作する。
systemd タイマーの利点:
- ジャーナル(journald)との統合によるログ管理
- サービスユニットの全機能を活用可能(依存関係、リソース制限など)
- カレンダー表記による柔軟なスケジューリング
- Persistent オプションによる実行漏れの防止
systemd-analyze calendarによる事前検証
8.2 タイマーユニットの作成
タイマーを作成するには、サービスユニット(.service)とタイマーユニット(.timer)の2つのファイルが必要となる。
# サービスユニット: /etc/systemd/system/backup.service
[Unit]
Description=Daily Database Backup
After=network.target postgresql.service
[Service]
Type=oneshot
User=backup
Group=backup
ExecStart=/usr/local/bin/db_backup.sh
StandardOutput=journal
StandardError=journal
# リソース制限
MemoryLimit=512M
CPUQuota=50%
Nice=10
IOSchedulingClass=idle
# タイマーユニット: /etc/systemd/system/backup.timer
[Unit]
Description=Run Database Backup Daily
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=600
AccuracySec=1min
[Install]
WantedBy=timers.target
# タイマーの有効化と起動
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now backup.timer
# タイマーの状態確認
$ systemctl status backup.timer
● backup.timer - Run Database Backup Daily
Loaded: loaded (/etc/systemd/system/backup.timer; enabled; vendor preset: disabled)
Active: active (waiting) since Mon 2026-04-06 09:00:00 JST; 4 days ago
Until: Mon 2026-04-06 09:00:00 JST; 4 days ago
Trigger: Sat Apr 11 02:00:00 2026; 15h left
Triggers: ● backup.service
# 全タイマーの一覧表示
$ systemctl list-timers --all
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sat 2026-04-11 02:00:00 JST 15h left Fri 2026-04-10 02:05:23 JST 8h ago backup.timer backup.service
Sat 2026-04-11 00:00:00 JST 13h left Fri 2026-04-10 00:00:00 JST 10h ago logrotate.timer logrotate.service
Sat 2026-04-11 06:30:00 JST 20h left Fri 2026-04-10 06:30:12 JST 4h ago fstrim.timer fstrim.service
8.3 OnCalendar による時刻指定
OnCalendar は非常に柔軟な時刻指定形式を提供する。
# OnCalendar の書式
# DayOfWeek Year-Month-Day Hour:Minute:Second
# 具体例
OnCalendar=*-*-* 02:00:00 # 毎日 02:00
OnCalendar=Mon *-*-* 09:00:00 # 毎週月曜 09:00
OnCalendar=*-*-01 00:00:00 # 毎月1日 00:00
OnCalendar=*-01-01 00:00:00 # 毎年1月1日 00:00
OnCalendar=Mon..Fri *-*-* 09:00:00 # 平日の 09:00
OnCalendar=*-*-* *:00:00 # 毎時 0分
OnCalendar=*-*-* *:*:00 # 毎分(秒を省略可)
OnCalendar=*-*-* 00/6:00:00 # 6時間ごと(0, 6, 12, 18時)
OnCalendar=Sat *-*-1..7 02:00:00 # 毎月第1土曜日 02:00
# 簡略表記
OnCalendar=hourly # 毎時
OnCalendar=daily # 毎日 00:00
OnCalendar=weekly # 毎週月曜 00:00
OnCalendar=monthly # 毎月1日 00:00
OnCalendar=yearly # 毎年1月1日 00:00
# systemd-analyze calendar で次回実行時刻を確認
$ systemd-analyze calendar "*-*-* 02:00:00"
Original form: *-*-* 02:00:00
Normalized form: *-*-* 02:00:00
Next elapse: Sat 2026-04-11 02:00:00 JST
(in UTC): Fri 2026-04-10 17:00:00 UTC
From now: 15h 30min left
$ systemd-analyze calendar "Mon *-*-* 09:00:00" --iterations=5
Original form: Mon *-*-* 09:00:00
Normalized form: Mon *-*-* 09:00:00
Next elapse: Mon 2026-04-13 09:00:00 JST
From now: 3 days left
Iter. #2: Mon 2026-04-20 09:00:00 JST
Iter. #3: Mon 2026-04-27 09:00:00 JST
Iter. #4: Mon 2026-05-04 09:00:00 JST
Iter. #5: Mon 2026-05-11 09:00:00 JST
8.4 OnBootSec / OnUnitActiveSec
単調タイマー(monotonic timer)は、特定のイベントからの経過時間を基準にジョブを実行する。
# /etc/systemd/system/monitoring.timer
[Unit]
Description=System Monitoring Timer
[Timer]
# システム起動から5分後に初回実行
OnBootSec=5min
# 前回のサービス実行完了から10分後に再実行
OnUnitActiveSec=10min
# 精度
AccuracySec=1sec
[Install]
WantedBy=timers.target
利用可能な単調タイマーオプション:
| オプション | 基準イベント |
|---|---|
OnBootSec | システム起動 |
OnStartupSec | systemd 起動(ユーザーセッションの場合) |
OnActiveSec | タイマーユニット自体のアクティブ化 |
OnUnitActiveSec | 対応するサービスの最終アクティブ化 |
OnUnitInactiveSec | 対応するサービスの最終非アクティブ化 |
# 複合的な設定例(起動後 + 定期実行)
[Timer]
OnBootSec=2min
OnUnitActiveSec=15min
8.5 Persistent オプション
Persistent=true を設定すると、システム停止中にスケジュールされていたジョブが次回起動時に実行される(anacron と同様の機能)。
[Timer]
OnCalendar=daily
Persistent=true # システム停止中の実行漏れを防止
# Persistent の動作確認
$ systemctl show backup.timer | grep -E "LastTrigger|NextElapse"
LastTriggerUSec=Fri 2026-04-10 02:05:23 JST
NextElapseUSecRealtime=Sat 2026-04-11 02:00:00 JST
8.6 一時的タイマー (systemd-run)
systemd-run を使用すると、ユニットファイルを作成せずに一時的なタイマーを設定できる。
# 30分後にコマンドを実行
$ sudo systemd-run --on-active=30min /usr/local/bin/cleanup.sh
Running timer as unit: run-r1234567890.timer
Will run service as unit: run-r1234567890.service
# 特定の時刻に実行
$ sudo systemd-run --on-calendar="2026-04-11 15:00:00" /usr/local/bin/report.sh
# ユーザーセッションで一時タイマー
$ systemd-run --user --on-active=1h /home/user/scripts/task.sh
# 一時タイマーの確認
$ systemctl list-timers --all | grep run-
9. cron vs systemd タイマー比較
| 機能 | cron | systemd タイマー |
|---|---|---|
| 最小実行間隔 | 1分 | 1秒(マイクロ秒精度も可) |
| カレンダー表記 | 5フィールド形式 | ISO 8601 ベース |
| ログ管理 | syslog / メール | journald 統合 |
| 依存関係管理 | なし | ユニットの依存関係で制御可能 |
| リソース制限 | なし | cgroups ベースの制限 |
| 実行漏れ防止 | なし(anacron が必要) | Persistent=true |
| ランダム遅延 | なし(RANDOM_DELAY は anacron のみ) | RandomizedDelaySec |
| 設定の複雑さ | 1行で記述可能 | 2つのユニットファイルが必要 |
| ユーザー管理 | crontab -e で簡単 | ~/.config/systemd/user/ に配置 |
| 状態確認 | crontab -l のみ | systemctl list-timers で詳細表示 |
| イベント駆動 | 時刻のみ | 起動後、ユニット変化後なども可 |
| テスト実行 | コマンドを手動実行 | systemctl start service.service |
| セキュリティ | cron.allow/deny | SystemCallFilter, ProtectSystem 等 |
推奨される使い分け:
-
cron が適している場合:
- 単純な定期実行タスク
- 既存システムとの互換性が重要
- クイックに設定したい場合
-
systemd タイマーが適している場合:
- 依存関係やリソース制限が必要
- 詳細なログ管理が必要
- Persistent 実行が必要
- セキュリティの強化が必要
10. cron ジョブのログとモニタリング
10.1 ログの確認方法
# RHEL系: cron ログの確認
$ sudo grep CRON /var/log/cron
Apr 10 02:00:01 server CROND[12345]: (root) CMD (/usr/local/bin/backup.sh)
Apr 10 02:00:01 server CROND[12346]: (user) CMD (/home/user/scripts/monitoring.sh)
# Debian系: syslog から確認
$ sudo grep CRON /var/log/syslog
Apr 10 02:00:01 server CRON[12345]: (root) CMD (/usr/local/bin/backup.sh)
# journald を使用する場合
$ journalctl -u crond --since today
$ journalctl -u cron --since "2026-04-10 02:00:00" --until "2026-04-10 03:00:00"
# systemd タイマーのログ
$ journalctl -u backup.service --since today
Apr 10 02:00:01 server systemd[1]: Starting Daily Database Backup...
Apr 10 02:05:23 server db_backup.sh[12345]: Backup completed successfully
Apr 10 02:05:23 server systemd[1]: backup.service: Deactivated successfully.
Apr 10 02:05:23 server systemd[1]: Finished Daily Database Backup.
10.2 メール通知
cron はジョブの標準出力・標準エラー出力をメールで送信する。
# crontab での MAILTO 設定
MAILTO=admin@example.com
# 複数宛先
MAILTO="admin@example.com,ops@example.com"
# メール送信を無効にする
MAILTO=""
# メール送信を無効にしつつ、ログを残す方法
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
# 出力が空の場合はメールを送信しない(cronie の -n オプション)
CRONDARGS="-n"
10.3 モニタリングの実装
#!/bin/bash
# /usr/local/bin/cron_wrapper.sh
# cron ジョブのラッパースクリプト(モニタリング対応)
JOB_NAME="$1"
shift
COMMAND="$@"
LOG_FILE="/var/log/cron_jobs/${JOB_NAME}.log"
LOCK_FILE="/var/run/cron_jobs/${JOB_NAME}.lock"
METRICS_FILE="/var/lib/node_exporter/textfile_collector/${JOB_NAME}.prom"
# ディレクトリの作成
mkdir -p /var/log/cron_jobs /var/run/cron_jobs /var/lib/node_exporter/textfile_collector
# 開始時刻の記録
START_TIME=$(date +%s)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting: ${JOB_NAME}" >> "${LOG_FILE}"
# コマンド実行
eval "${COMMAND}" >> "${LOG_FILE}" 2>&1
EXIT_CODE=$?
# 終了時刻と実行時間の計算
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Finished: ${JOB_NAME} (exit=${EXIT_CODE}, duration=${DURATION}s)" >> "${LOG_FILE}"
# Prometheus メトリクスの出力
cat > "${METRICS_FILE}" << EOF
# HELP cron_job_exit_code Exit code of the last cron job execution
# TYPE cron_job_exit_code gauge
cron_job_exit_code{job="${JOB_NAME}"} ${EXIT_CODE}
# HELP cron_job_duration_seconds Duration of the last cron job execution
# TYPE cron_job_duration_seconds gauge
cron_job_duration_seconds{job="${JOB_NAME}"} ${DURATION}
# HELP cron_job_last_run_timestamp_seconds Timestamp of the last cron job execution
# TYPE cron_job_last_run_timestamp_seconds gauge
cron_job_last_run_timestamp_seconds{job="${JOB_NAME}"} ${END_TIME}
EOF
# エラー時の通知
if [ ${EXIT_CODE} -ne 0 ]; then
echo "ALERT: Cron job '${JOB_NAME}' failed with exit code ${EXIT_CODE}" | \
mail -s "[ALERT] Cron Job Failure: ${JOB_NAME}" admin@example.com
fi
exit ${EXIT_CODE}
# ラッパースクリプトの使用例(crontab 内)
0 2 * * * /usr/local/bin/cron_wrapper.sh db_backup /usr/local/bin/db_backup.sh
11. cron のエラーハンドリング
11.1 終了コードの処理
#!/bin/bash
# /usr/local/bin/backup_with_error_handling.sh
set -euo pipefail
# エラーハンドラ
cleanup() {
local exit_code=$?
if [ ${exit_code} -ne 0 ]; then
echo "[ERROR] Backup failed with exit code ${exit_code}" >&2
# アラート送信
curl -s -X POST "https://hooks.slack.com/services/xxx/yyy/zzz" \
-H 'Content-Type: application/json' \
-d "{\"text\": \"Backup failed on $(hostname) at $(date)\"}"
fi
# 一時ファイルの清掃
rm -f /tmp/backup_*.tmp
exit ${exit_code}
}
trap cleanup EXIT
# メイン処理
echo "Starting backup at $(date)"
pg_dump mydb > /tmp/backup_$(date +%Y%m%d).sql
gzip /tmp/backup_$(date +%Y%m%d).sql
aws s3 cp /tmp/backup_$(date +%Y%m%d).sql.gz s3://my-backup-bucket/
echo "Backup completed at $(date)"
11.2 ロック機構の実装
同じジョブが同時に複数実行されることを防ぐためのロック機構。
#!/bin/bash
# flock を使用したロック(推奨)
exec 200>/var/lock/my_cron_job.lock
flock -n 200 || { echo "Job is already running"; exit 1; }
# メイン処理
echo "Processing..."
sleep 60
echo "Done"
# crontab 内で直接 flock を使用する方法
*/5 * * * * flock -n /var/lock/monitoring.lock /usr/local/bin/monitoring.sh
# タイムアウト付き flock
*/5 * * * * flock -w 60 /var/lock/monitoring.lock /usr/local/bin/monitoring.sh
# PIDファイルを使用したロック(レガシー手法)
#!/bin/bash
PIDFILE="/var/run/my_job.pid"
if [ -f "${PIDFILE}" ]; then
PID=$(cat "${PIDFILE}")
if kill -0 "${PID}" 2>/dev/null; then
echo "Process ${PID} is still running"
exit 1
else
echo "Stale PID file found, removing"
rm -f "${PIDFILE}"
fi
fi
echo $$ > "${PIDFILE}"
trap "rm -f ${PIDFILE}" EXIT
# メイン処理
11.3 タイムアウト処理
# timeout コマンドの使用
*/30 * * * * timeout 1800 /usr/local/bin/long_running_job.sh
# timeout + flock の組み合わせ
*/30 * * * * flock -n /var/lock/job.lock timeout 1800 /usr/local/bin/job.sh
# systemd タイマーでのタイムアウト設定
# /etc/systemd/system/job.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/job.sh
TimeoutStartSec=1800
12. cron の環境変数
12.1 デフォルト環境変数
cron は非常に限定的な環境でコマンドを実行する。これは多くの問題の原因となる。
# cron のデフォルト環境変数
SHELL=/bin/sh
PATH=/usr/bin:/bin
HOME=/home/username
LOGNAME=username
# 通常のログインシェルとの比較
# ログインシェル
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/user/.local/bin
# cron 環境
$ crontab -l
* * * * * echo "PATH=$PATH" >> /tmp/cron_env.log
$ cat /tmp/cron_env.log
PATH=/usr/bin:/bin
12.2 環境変数の設定方法
# 方法1: crontab 内で直接設定
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
JAVA_HOME=/usr/lib/jvm/java-17
NODE_PATH=/usr/local/lib/node_modules
MAILTO=admin@example.com
0 2 * * * /usr/local/bin/backup.sh
# 方法2: スクリプト内で環境を読み込み
0 2 * * * . /etc/profile; /usr/local/bin/backup.sh
# 方法3: env コマンドを使用
0 2 * * * env PATH=/usr/local/bin:/usr/bin:/bin JAVA_HOME=/usr/lib/jvm/java-17 /usr/local/bin/backup.sh
# 方法4: スクリプト内で明示的に設定
#!/bin/bash
source /etc/profile
source ~/.bashrc
export PATH="/usr/local/sbin:/usr/local/bin:$PATH"
# メイン処理
12.3 PATH の取り扱い
# 推奨: コマンドのフルパスを使用する
# 悪い例
0 2 * * * mysqldump mydb > /tmp/backup.sql
# 良い例
0 2 * * * /usr/bin/mysqldump mydb > /tmp/backup.sql
# コマンドのパス確認
$ which mysqldump
/usr/bin/mysqldump
$ type -a python3
python3 is /usr/bin/python3
python3 is /usr/local/bin/python3
13. ベストプラクティス
1. ログを残す
# 標準出力と標準エラー出力をログに記録
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
# ローテーション対応のログ
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup_$(date +\%Y\%m\%d).log 2>&1
2. ロック機構を使う
# 同時実行を防止
*/5 * * * * flock -n /var/lock/job.lock /usr/local/bin/job.sh
3. タイムアウトを設定する
# 長時間実行を防止
0 2 * * * timeout 3600 /usr/local/bin/job.sh
4. コメントを残す
# === データベースバックアップ ===
# 担当: 運用チーム
# 最終更新: 2026-04-10
# 関連ドキュメント: https://wiki.example.com/backup
0 2 * * * /usr/local/bin/db_backup.sh >> /var/log/db_backup.log 2>&1
5. バックアップを取る
# crontab のバックアップスクリプト
#!/bin/bash
BACKUP_DIR="/opt/crontab_backups"
mkdir -p "${BACKUP_DIR}"
DATE=$(date +%Y%m%d_%H%M%S)
# 全ユーザーの crontab をバックアップ
for user in $(cut -f1 -d: /etc/passwd); do
crontab -u "${user}" -l > "${BACKUP_DIR}/${user}_${DATE}.crontab" 2>/dev/null
done
# システム crontab のバックアップ
cp /etc/crontab "${BACKUP_DIR}/system_${DATE}.crontab"
cp -r /etc/cron.d/ "${BACKUP_DIR}/cron.d_${DATE}/"
# 30日以上前のバックアップを削除
find "${BACKUP_DIR}" -type f -mtime +30 -delete
6. 実行タイミングをずらす
# 悪い例: 全てのジョブが同時刻に集中
0 0 * * * /job1.sh
0 0 * * * /job2.sh
0 0 * * * /job3.sh
# 良い例: 適度にタイミングをずらす
0 0 * * * /job1.sh
10 0 * * * /job2.sh
20 0 * * * /job3.sh
# systemd タイマーの場合は RandomizedDelaySec を活用
[Timer]
OnCalendar=daily
RandomizedDelaySec=1800 # 最大30分のランダム遅延
7. 冪等性を保証する
#!/bin/bash
# 冪等なバックアップスクリプト
BACKUP_FILE="/backup/db_$(date +%Y%m%d).sql.gz"
# 既にバックアップが存在する場合はスキップ
if [ -f "${BACKUP_FILE}" ]; then
echo "Backup already exists: ${BACKUP_FILE}"
exit 0
fi
pg_dump mydb | gzip > "${BACKUP_FILE}.tmp"
mv "${BACKUP_FILE}.tmp" "${BACKUP_FILE}"
14. よくある落とし穴と対策
落とし穴 1: PATH が通っていない
# 問題: cron 環境では PATH が制限される
*/5 * * * * python3 /home/user/script.py # 失敗する可能性
# 対策: フルパスを使用
*/5 * * * * /usr/bin/python3 /home/user/script.py
落とし穴 2: パーセント記号のエスケープ
# 問題: cron では % が改行として解釈される
0 2 * * * echo "Date: $(date +%Y-%m-%d)" >> /tmp/log # 失敗
# 対策: % をバックスラッシュでエスケープ
0 2 * * * echo "Date: $(date +\%Y-\%m-\%d)" >> /tmp/log
落とし穴 3: crontab -r の誤操作
# 問題: crontab -r は確認なしで全エントリを削除
$ crontab -r # キーボードで e と r は隣接 → 誤操作リスク
# 対策1: エイリアスで確認プロンプトを追加
alias crontab='crontab -i'
# 対策2: crontab の定期バックアップ
0 * * * * crontab -l > /home/user/.crontab_backup
落とし穴 4: タイムゾーンの問題
# cron はシステムのタイムゾーンを使用する
$ timedatectl
Local time: Fri 2026-04-10 10:30:00 JST
Universal time: Fri 2026-04-10 01:30:00 UTC
RTC time: Fri 2026-04-10 01:30:00
Time zone: Asia/Tokyo (JST, +0900)
# cronie では CRON_TZ 変数でタイムゾーンを変更可能
CRON_TZ=America/New_York
0 9 * * * /usr/local/bin/us_report.sh # ニューヨーク時間の午前9時
# systemd タイマーではタイムゾーンは UTC が基本
# ローカルタイムを明示する場合
OnCalendar=*-*-* 02:00:00 Asia/Tokyo
落とし穴 5: 日と曜日の同時指定
# 注意: 日と曜日を同時に指定すると OR 条件になる
# 以下は「毎月15日 または 毎週金曜日」に実行される
0 0 15 * 5 /usr/local/bin/job.sh
# 「毎月15日の金曜日のみ」にしたい場合はスクリプト内でチェック
0 0 15 * * [ "$(date +\%u)" = "5" ] && /usr/local/bin/job.sh
落とし穴 6: 出力の大量生成
# 問題: 大量の出力がメールキューを圧迫
*/5 * * * * /usr/local/bin/verbose_script.sh # 大量のメールが送信される
# 対策: 出力をログにリダイレクトし、メール送信を抑制
*/5 * * * * /usr/local/bin/verbose_script.sh >> /var/log/verbose.log 2>&1
15. トラブルシューティング
ジョブが実行されない
# チェックリスト
# 1. cron デーモンが動作しているか
$ systemctl status crond
# 2. crontab が正しく設定されているか
$ crontab -l
# 3. cron ログにエラーがないか
$ sudo grep CRON /var/log/cron
$ sudo journalctl -u crond --since "1 hour ago"
# 4. スクリプトに実行権限があるか
$ ls -la /usr/local/bin/backup.sh
$ chmod +x /usr/local/bin/backup.sh
# 5. スクリプトが正しく動作するか(手動テスト)
$ /usr/local/bin/backup.sh
# 6. 環境変数の問題がないか
$ env -i SHELL=/bin/sh PATH=/usr/bin:/bin /usr/local/bin/backup.sh
# 7. cron.allow / cron.deny に制限がないか
$ cat /etc/cron.allow
$ cat /etc/cron.deny
# 8. SELinux のコンテキストが正しいか
$ ls -Z /usr/local/bin/backup.sh
$ ausearch -m avc --start today
systemd タイマーが動作しない
# チェックリスト
# 1. タイマーが有効か
$ systemctl is-enabled backup.timer
$ systemctl status backup.timer
# 2. 対応するサービスの状態
$ systemctl status backup.service
# 3. サービスのログ確認
$ journalctl -u backup.service -n 50
# 4. タイマーの次回実行時刻
$ systemctl list-timers backup.timer
# 5. ユニットファイルの構文チェック
$ systemd-analyze verify /etc/systemd/system/backup.timer
$ systemd-analyze verify /etc/systemd/system/backup.service
# 6. 手動実行テスト
$ sudo systemctl start backup.service
$ journalctl -u backup.service -f
16. 参考文献
-
man ページ:
man 5 crontab- crontab ファイルの書式man 1 crontab- crontab コマンドの使い方man 8 cron- cron デーモンの説明man 8 anacron- anacron の説明man 1 at- at コマンドの使い方man 5 systemd.timer- systemd タイマーユニットman 7 systemd.time- systemd 時刻表記
-
公式ドキュメント:
- systemd タイマー: https://www.freedesktop.org/software/systemd/man/systemd.timer.html
- cronie プロジェクト: https://github.com/cronie-crond/cronie
-
関連ツール:
- crontab.guru: https://crontab.guru/ - cron 表現のオンラインエディタ
- Cronitor: https://cronitor.io/ - cron ジョブのモニタリングサービス
- Healthchecks.io: https://healthchecks.io/ - ジョブ監視 SaaS
-
書籍:
- 「Linuxシステム管理標準教科書」LPI-Japan
- 「UNIX and Linux System Administration Handbook」Evi Nemeth 他
- 「Linux Command Line and Shell Scripting Bible」Richard Blum
本ドキュメントは 2026年4月時点の情報に基づいています。最新の情報は各ソフトウェアの公式ドキュメントを参照してください。