定期実行スクリプトに「メンテナンスウィンドウ(許可時間帯)」を組み込むことで、許可された時間帯だけ処理を実行し、それ以外はスキップするように制御できます。dateコマンドで現在の時刻・曜日を取得し、条件分岐でウィンドウ外を検知する仕組みは、数十行のシェルスクリプトで実装できます。
この記事では、bashのdateコマンドを使った時刻・曜日チェックの実装パターンを、RHEL 9 / Rocky Linux 9 で動作確認した実際のスクリプト例を交えながら解説します。
この記事のポイント
・dateコマンドの書式指定で現在時刻・曜日番号を数値として取得できる
・時刻チェックは「開始時刻 <= 現在時刻 < 終了時刻」の整数比較で実装する
・日付跨ぎ(23:00~翌1:00)は時刻をHHMM形式の整数に変換して正しく判定する
・曜日・時刻・ホスト名の複合条件で本番環境の運用ルールをコードに落とし込める
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
メンテナンスウィンドウが必要な場面
以下のようなケースでメンテナンスウィンドウの設計が役立ちます。・バックアップスクリプト:業務時間内は動かしたくない(I/O負荷を避けるため)
・DBメンテナンス:深夜のVACUUMやREBUILDを特定時間帯に限定したい
・バッチ更新処理:土日の自動配信を止めて月曜朝に一括送信したい
・外部API呼び出し:相手方のメンテナンス時間帯を避けてリトライしたい
cronの `*/5 * * * *` のような実行スケジュールで細かい時間帯制御ができないときや、スクリプト自体に「今は動くべき時間か?」を判断させたいときに、本記事のパターンが使えます。
dateコマンドで時刻・曜日を取得する基本
1. 時刻・曜日番号の取得
時刻の取得には `date` コマンドの書式指定を使います。# 現在時刻をHHMM形式(例: 0300、2345)で取得する $ date +%H%M 0315 # 時間・分を別々に取得する $ date +%H 03 $ date +%M 15 # 曜日番号を取得する(0=日曜、1=月曜 ... 6=土曜) $ date +%w 5 # 曜日名(短縮形)で取得する $ date +%a Fri
2. 時刻をHHMM整数に変換して比較する
時刻の範囲チェックには、HHMM形式の整数比較が最もシンプルです。例えば「0:00~6:00」なら `0000` ~ `0600` の範囲に現在時刻が入っているかを整数で比較します。# HHMM形式の整数として現在時刻を取得する CURRENT_TIME=$(date +%H%M) # 範囲チェック(0000 <= CURRENT_TIME < 0600) if [[ "${CURRENT_TIME}" -ge 0 && "${CURRENT_TIME}" -lt 600 ]]; then echo "メンテナンスウィンドウ内(深夜0時~6時)" else echo "メンテナンスウィンドウ外" fi
時刻チェックの実装パターン
1. 日付跨ぎなし(同日内の時間帯)
「平日の9:00~18:00は実行スキップ(業務時間外のみ実行)」のような同日内の時間帯チェックです。#!/bin/bash # 業務時間(09:00 ~ 18:00)は実行をスキップする CURRENT_TIME=$(date +%H%M) BUSINESS_START=900 # 09:00 BUSINESS_END=1800 # 18:00 if [[ "${CURRENT_TIME}" -ge "${BUSINESS_START}" && "${CURRENT_TIME}" -lt "${BUSINESS_END}" ]]; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] 業務時間内のためスキップします(現在: ${CURRENT_TIME})" >&2 exit 0 fi echo "[$(date '+%Y-%m-%d %H:%M:%S')] 処理を開始します。" # 実際の処理をここに書く
2. 日付跨ぎあり(深夜帯のウィンドウ)
「深夜23:00~翌1:00のみ実行」のような日付を跨ぐケースは、単純な整数比較では正しく判定できません。「ウィンドウ外を検知する」方向で考えると簡単に実装できます。#!/bin/bash # 深夜23:00 ~ 翌01:00のみ実行する(日付跨ぎウィンドウ) CURRENT_TIME=$(date +%H%M) WINDOW_START=2300 # 23:00 WINDOW_END=100 # 01:00 # ウィンドウ内: CURRENT_TIME >= 2300 OR CURRENT_TIME < 100 is_in_window() { local t=$1 if [[ "${t}" -ge "${WINDOW_START}" || "${t}" -lt "${WINDOW_END}" ]]; then return 0 # ウィンドウ内 fi return 1 # ウィンドウ外 } if ! is_in_window "${CURRENT_TIME}"; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] メンテナンスウィンドウ外のためスキップします。" >&2 exit 0 fi echo "[$(date '+%Y-%m-%d %H:%M:%S')] メンテナンスウィンドウ内。処理を開始します。" # 実際の処理をここに書く
# 現在時刻が03:15の場合(ウィンドウ内) $ bash /opt/scripts/maintenance_job.sh [2026-08-15 03:15:22] メンテナンスウィンドウ内。処理を開始します。 # 現在時刻が14:30の場合(ウィンドウ外) $ bash /opt/scripts/maintenance_job.sh [2026-08-15 14:30:05] メンテナンスウィンドウ外のためスキップします。 $ echo $? 0
曜日チェックの実装パターン
1. 土日をスキップする
`date +%w` の戻り値は `0`(日曜)~ `6`(土曜)の整数です。#!/bin/bash # 土日(曜日番号0=日曜, 6=土曜)はスキップする WEEKDAY=$(date +%w) if [[ "${WEEKDAY}" -eq 0 || "${WEEKDAY}" -eq 6 ]]; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] 土日のためスキップします。" >&2 exit 0 fi echo "[$(date '+%Y-%m-%d %H:%M:%S')] 平日。処理を開始します。"
2. 特定曜日だけ実行する
毎週月曜日の深夜だけ実行するような「曜日指定実行」は以下のように実装します。#!/bin/bash # 月曜日(曜日番号1)のみ実行する WEEKDAY=$(date +%w) TARGET_WEEKDAY=1 # 月曜 if [[ "${WEEKDAY}" -ne "${TARGET_WEEKDAY}" ]]; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] 月曜日以外のためスキップします(曜日番号: ${WEEKDAY})" >&2 exit 0 fi echo "[$(date '+%Y-%m-%d %H:%M:%S')] 月曜日。週次処理を開始します。"
時刻・曜日を組み合わせた実践スクリプト
「平日の深夜1:00~4:00のみ実行」という典型的なメンテナンスウィンドウを実装した完成例です。#!/bin/bash # メンテナンスウィンドウ付きバッチスクリプト # 対象: 平日(月~金)の01:00 ~ 04:00のみ実行 LOG_PREFIX="[$(date '+%Y-%m-%d %H:%M:%S')]" CURRENT_TIME=$(date +%H%M) WEEKDAY=$(date +%w) # 関数: メンテナンスウィンドウ内か判定する(0=OK, 1=NG) check_window() { local time=$1 local day=$2 # 土日チェック(0=日曜, 6=土曜) if [[ "${day}" -eq 0 || "${day}" -eq 6 ]]; then echo "${LOG_PREFIX} 土日のためスキップ(曜日番号: ${day})" >&2 return 1 fi # 時刻チェック(01:00 = 100 ~ 04:00 = 400) if [[ "${time}" -lt 100 || "${time}" -ge 400 ]]; then echo "${LOG_PREFIX} ウィンドウ外のためスキップ(現在時刻: ${time})" >&2 return 1 fi return 0 } if ! check_window "${CURRENT_TIME}" "${WEEKDAY}"; then exit 0 fi echo "${LOG_PREFIX} メンテナンスウィンドウ内。処理を開始します。" # ---- 実際の処理 ---- # ... # -------------------- echo "${LOG_PREFIX} 処理が完了しました。"
cronとの組み合わせ実践パターン
crontabでは分・時間単位の指定しかできないため、「平日の1:00~4:00の間で5分ごとに実行し、スクリプト側でウィンドウを判定する」設計が現場でよく使われます。# /etc/cron.d/maintenance_job # 毎日1:00 ~ 4:00の間に5分ごとに実行(ウィンドウ判定はスクリプト側) */5 1-3 * * 1-5 root /opt/scripts/maintenance_job.sh >> /var/log/maintenance_job.log 2>&1
実際の cronログ(/var/log/cron から抜粋):
Aug 15 01:05:01 server01 CROND[12341]: (root) CMD (/opt/scripts/maintenance_job.sh >> /var/log/maintenance_job.log 2>&1) Aug 15 01:10:01 server01 CROND[12456]: (root) CMD (/opt/scripts/maintenance_job.sh >> /var/log/maintenance_job.log 2>&1) Aug 15 04:05:01 server01 CROND[13789]: (root) CMD (/opt/scripts/maintenance_job.sh >> /var/log/maintenance_job.log 2>&1)
よくある失敗とトラブルシュート
「HHMM の先頭が 0 で始まると8進数として解釈されてエラーになる」bash の算術評価では `08` や `09` が8進数として認識されてエラーになります。HHMM比較は
[[ ]](二重ブラケット)の数値比較で実施することでこの問題を回避できます。[ ](単一ブラケット)の場合は `10#${CURRENT_TIME}` のように明示的に10進数指定してください。# NG: 単一ブラケットで先頭0の比較(08, 09が8進数エラーになる場合がある) [ "${CURRENT_TIME}" -ge 800 ] # OK: 二重ブラケットを使う(bash拡張構文で8進数解釈を回避できる) [[ "${CURRENT_TIME}" -ge 800 ]] # OK: 10進数を明示する(POSIX sh互換が必要な場合) [ "$((10#${CURRENT_TIME}))" -ge 800 ]
スクリプトが別のタイムゾーン設定のユーザーで動く場合や、Docker コンテナ内では `TZ` 環境変数が意図しない値になっていることがあります。スクリプト冒頭で `TZ` を明示的に設定しましょう:
#!/bin/bash # タイムゾーンをJSTに固定する export TZ=Asia/Tokyo CURRENT_TIME=$(date +%H%M) WEEKDAY=$(date +%w)
メンテナンスウィンドウの判定は「実行開始時」にしか行われません。処理が長引いてウィンドウ終了時刻を過ぎても、途中停止はされません。長時間処理は `timeout` コマンドで最大実行時間を設定するか、処理の節目(ループ内など)で定期的に時刻チェックを行う設計が有効です:
# timeoutコマンドでウィンドウ終了前に強制停止させる(例: 3時間で停止) timeout 10800 /opt/scripts/long_maintenance_job.sh # または処理ループ内でも時刻チェックを挟む for item in "${items[@]}"; do # ウィンドウが切れていたら中断する CURRENT_TIME=$(date +%H%M) if [[ "${CURRENT_TIME}" -ge 400 ]]; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] ウィンドウ終了のため処理を中断します。" >&2 break fi process_item "${item}" done
本記事のまとめ
| やりたいこと | 実装方法 |
|---|---|
| 現在時刻をHHMM整数で取得する | CURRENT_TIME=$(date +%H%M) |
| 曜日番号を取得する(0=日曜) | WEEKDAY=$(date +%w) |
| 同日内の時間帯を確認する | [[ CURRENT_TIME -ge 開始 && CURRENT_TIME -lt 終了 ]] |
| 日付跨ぎの時間帯を確認する | [[ CURRENT_TIME -ge 2300 || CURRENT_TIME -lt 100 ]] |
| 土日をスキップする | [[ WEEKDAY -eq 0 || WEEKDAY -eq 6 ]] |
| タイムゾーンを固定する | export TZ=Asia/Tokyo |
シェルスクリプト講座を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:シェルスクリプトでSFTPファイル転送を自動化する設計|バッチモードとSSH鍵認証で安全な自動転送を実装する方法
- この記事の属するカテゴリ:シェルスクリプトへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます