ここでは、これまで議論した内容を「/etc/cron.d を直接編集する場合」にフォーカスして整理します。併せて、ジョブの実行ログを“自前のログファイルに出力”する実践手順を詳しく解説します。
目次
- そもそもcronとは?
- [なぜ
/etc/cron.dを使うのか](#なぜ/etc/cron.dを使うのか) - 書式(/etc/cron.d)
- コメントアウト(無効化)
- “自前のログファイル”に出力する(推奨フロー)
- [ 同時実行の防止(
flock)](# 同時実行の防止(flock)) - よくある失敗と対策(チェックリスト)
- 具体例(20分おきに実行、排他+自前ログ)
- まとめ
そもそもcronとは?
cron は Unix/Linux で定期的にコマンドやスクリプトを自動実行する仕組みです。
常駐デーモン(多くのディストリでは crond サービス)が、設定ファイル(crontab)を監視・実行します。
設定ファイル
/etc/cron.d/に保管 されており、ここに置かれたファイルが実行されていく。
なぜ /etc/cron.d を使うのか
-
ユーザ欄付き(7フィールド) で、実行ユーザを行内で指定できる(例:
root)。 - 設定をファイル単位で分離でき、アプリごと・用途ごとに管理しやすい。
- サービス配布やコンフィグ管理(Ansible/Chef等)との相性が良い。
参考:ユーザごとの
crontab -eは**ユーザ欄なし(6フィールド)**で、そのユーザ権限で実行されます。/etc/crontabは/etc/cron.dと同形式。
書式(/etc/cron.d)
分 時 日 月 曜日 ユーザ コマンド
-
例:20分おきに root で実行(bash でスクリプトを叩く)
/20 * * * * root /bin/bash /opt/scripts/process.sh >> /var/log/process.log 2>&1 -
注意
-
ユーザ欄は必須(
rootなど)。ここで実行権限を決めるのでsudoは不要です。 -
インラインコメント不可:コマンドの後ろに
#を置いても“コマンドの一部”。コメントは別行で#を先頭に。
-
ユーザ欄は必須(
実行時間の指定について
毎日13:20に実行したい場合:20 13 * * *
20分間隔で実行したい場合:/20 * * * *
コメントアウト(無効化)
-
行頭に
#を付ければその行は無効化されます。空行も無視されます。# 0 * * * * root /opt/scripts/job.sh 15 * * * * root /opt/scripts/job2.sh -
ファイルごと停止したい場合は、
/etc/cron.d.disabled等に退避(移動)するのが確実。
“自前のログファイル”に出力する(推奨フロー)
1) cron 行末でリダイレクト
-
追記し、標準エラーも束ねる:
*/20 * * * * root /bin/bash /opt/scripts/process.sh >> /var/log/process.log 2>&1
2) スクリプト側でログ整形(タイムスタンプ+トレース)
#!/usr/bin/env bash
set -euo pipefail
# 失敗箇所を追いやすくする(詳細が欲しければ -x も追加)
# set -x
# 1行で“以後の出力すべて”をファイルへ送る
exec >>/var/log/process.log 2>&1
echo "[$(date '+%F %T')] start pid=$$"
# ---- 本処理 ここから ----
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cd /opt/scripts # 相対パスを使うなら先に移動
/usr/bin/curl -fsS https://example.com/health || {
echo "[$(date '+%F %T')] health check failed"
exit 1
}
# ---- 本処理 ここまで ----
rc=$?
echo "[$(date '+%F %T')] end rc=$rc"
exit "$rc"
ポイント
-
exec >>/var/log/process.log 2>&1で以後の標準出力・エラーを丸ごとファイルへ。cron 行末でのリダイレクトとどちらか片方でもOK(併用も害はない)。 -
PATHを明示、コマンドは極力フルパス(cron の環境は最小限)。 - 相対パスを使うなら 冒頭で
cd(cron 実行時の作業ディレクトリは通常/)。
3) ログ肥大化への備え(任意)
-
/etc/logrotate.d/processを用意してローテート:/var/log/process.log { weekly rotate 8 compress missingok notifempty create 0640 root root postrotate /usr/bin/killall -HUP rsyslogd 2>/dev/null || true endscript }
logrotate.dとは?
ログの自動ローテートを設定するファイル
同時実行の防止(flock)
ジョブが重なると不整合の元。排他ロックで多重起動を防ぎます。
*/20 * * * * root flock -n /run/process.lock /bin/bash /opt/scripts/process.sh >> /var/log/process.log 2>&1
-
-n:ロック取得できなければ即終了(待たない)。
よくある失敗と対策(チェックリスト)
-
権限:
- スクリプトに実行権限:
chmod +x /opt/scripts/process.sh - 上位ディレクトリの“x”権限(実行/探索権)が不足していないか:
namei -l /opt/scripts/process.sh
- スクリプトに実行権限:
-
改行コード:Windows 由来だと失敗(CRLF)。
dos2unixで LF に。 -
sudoは不要:/etc/cron.dではユーザ欄で権限を指定する(root)。sudoを書くと PATH でこけやすい。
具体例(20分おきに実行、排他+自前ログ)
/etc/cron.d/myapp
MAILTO=""
*/20 * * * * root flock -n /run/myapp.lock /bin/bash /opt/scripts/myapp.sh >> /var/log/myapp.log 2>&1
/opt/scripts/myapp.sh
#!/usr/bin/env bash
set -euo pipefail
exec >>/var/log/myapp.log 2>&1
echo "[$(date '+%F %T')] myapp start pid=$$"
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cd /opt/scripts
# 例:Nginx の稼働チェック
if ! pgrep -x nginx >/dev/null; then
echo "[$(date '+%F %T')] nginx not running"
exit 1
fi
echo "[$(date '+%F %T')] myapp done rc=0"
まとめ
-
/etc/cron.d は 7 フィールド(分・時・日・月・曜・ユーザ・コマンド)。ユーザ欄で権限を指定し、
sudoは不要。 -
ログは自前ファイルに出す:
>> /var/log/xxx.log 2>&1を cron 行またはスクリプト側execで設定。 - PATH 明示/絶対パス/作業ディレクトリ/改行コード/実行権限を整える。
-
flockで多重起動を防止し、必要なら logrotate でログ肥大化を抑制。