cron 表達式教學:五個欄位、語法差異與時區陷阱
DDEVELOPER
開發發布: 12 分鐘閱讀

cron 表達式教學:五個欄位、語法差異與時區陷阱

* * * * *:只用五個欄位,就能描述工作何時執行。不過,同一組表達式在不同排程器中,不一定有相同的意思。本文以常見的五欄位格式為起點,區分 POSIX 基本語法、Cronie 擴充語法及雲端服務的差異,說明設定排程前應確認的條件。

日文原文發布: 2026-05-11

cron 是什麼?以分鐘為單位的背景排程服務

cron 是 UNIX 類作業系統的時間排程服務,通常以背景常駐程式(daemon)運作。它每分鐘檢查排程表 crontab,符合條件時,就以子行程執行指定的指令。標準輸出與標準錯誤會依設定寄送電子郵件或寫入日誌。

即使使用容器、無伺服器服務或 CI/CD,仍會遇到 cron 的概念:

  • Kubernetes CronJob:依排程建立 Job,再由 Job 執行 Pod。
  • GitHub Actions:以 schedule 事件定期觸發工作流程。
  • AWS EventBridge Scheduler:由受管服務解讀 cron 表達式並呼叫目標。
  • systemd timer:另一種排程方式,使用自己的 OnCalendar 語法;轉換 cron 設定需要 systemd-cron 等額外工具。

共用 cron 的概念,不代表語法與執行保證完全相同。移植排程時,仍須查看目標環境的規格。

五個時間欄位,不等於完整的 crontab 設定

POSIX 的 crontab 規格定義「分、時、日期、月份、星期」五個時間欄位,後面再接要執行的指令,不含秒欄位。Vixie Cron 系列等實作另有環境變數設定及擴充記法;Cronie 文件描述的是其中一種實作,不應套用到所有 UNIX 系統與雲端服務。

cron 表達式只是排程部分。使用者的 crontab 在五個時間欄位後面接指令;Cronie 的系統 crontab 則還要在時間欄位與指令之間指定執行帳號。本文表格只列時間部分,含指令的範例則用於使用者 crontab。

# 使用者 crontab:五個時間欄位後面接指令
0 9 * * 1-5 /home/user/scripts/report.sh

請將範例路徑換成實際存在、且執行帳號有權限存取的檔案。單獨貼上五個時間欄位,並不會形成可執行的工作。

欄位範圍與基本運算符號

以下包含 Cronie 系列的擴充語法。POSIX 的星期範圍是 0–6,基本語法不包含斜線步進值,也不包含月份與星期的英文名稱。

分    時    日期    月份    星期
0–59  0–23  1–31    1–12    0–7(Cronie)
 *     *      *       *       *

表格若超出畫面寬度,可左右捲動。

欄位範圍注意事項
分0–59一小時內的分鐘
時0–2324 小時制
日期1–31指一個月中的第幾天;不存在的日期不會符合此條件,但仍須注意與星期的 OR 組合
月份1–12JAN–DEC 屬於實作擴充
星期0–7(Cronie)0 與 7 都是星期日,1 是星期一,6 是星期六

表格若超出畫面寬度,可左右捲動。

符號意義範例
*欄位內的所有值* * * * *:每分鐘
,列出多個值日期欄位的 1,15:1 日與 15 日
-包含兩端的範圍星期欄位的 1-5:星期一至星期五
/在欄位範圍內依步進值取值分鐘欄位的 */15:0、15、30、45 分

0 9 * * 1-5 表示星期一至星期五 09:00,不會排除國定假日。30 4 * * 0 是每週日 04:30;0 */2 * * * 是設定時區的 00:00、02:00、04:00,依此類推。0 0 1,15 * * 則是每月 1 日與 15 日的午夜。

常用的五欄位排程範例

下表適用於支援 Cronie 系列語法的五欄位排程器。用於使用者 crontab 時,還要接上指令;用於其他服務前,請先確認支援的語法。

表格若超出畫面寬度,可左右捲動。

執行時間cron 表達式
每分鐘* * * * *
每 5 分鐘*/5 * * * *
每 10 分鐘*/10 * * * *
每 15 分鐘*/15 * * * *
每小時的 0 分與 30 分0,30 * * * *
每小時整點0 * * * *
每天午夜0 0 * * *
每天 09:000 9 * * *
每天 02:000 2 * * *
星期一至星期五,09:00 至 18:00 的每個整點0 9-18 * * 1-5
每週一 09:000 9 * * 1
每週日 03:000 3 * * 0
每月 1 日午夜0 0 1 * *
每月 1 日與 15 日 09:000 9 1,15 * *
1、4、7、10 月的 1 日午夜0 0 1 1,4,7,10 *
每年 1 月 1 日午夜0 0 1 1 *
星期一至星期五中午0 12 * * 1-5

每月 1 日與 15 日是每月兩次,不是每隔 14 天。星期一至星期五的排程仍包含假日;每天 02:00 的備份也需要確認時區與日光節約時間的處理方式。

基本五欄位 cron 沒有「月底最後一天」的運算符號。0 0 28-31 * * 會在每月實際存在的 28 至 31 日都執行。可以在指令中判斷日期,或使用 EventBridge Scheduler 的 L 等有明確文件的擴充語法。

簡寫、六欄位與七欄位:不同實作的語法差異

Cronie 提供以下簡寫,用來取代時間欄位:

表格若超出畫面寬度,可左右捲動。

簡寫對應排程或行為
@yearly0 0 1 1 *
@monthly0 0 1 * *
@weekly0 0 * * 0
@daily0 0 * * *
@hourly0 * * * *
@reboot系統啟動後執行一次;Cronie 通常不會因為單純重新啟動 cron 服務而再次執行

Cronie 透過鎖定檔避免重複執行啟動工作。不要把 @reboot 當成服務重新啟動時的觸發機制;換用其他 cron 實作時,也要確認啟動條件。

Spring 在最前面加入秒欄位;Quartz 有六個必要欄位,最後可選填年份。EventBridge Scheduler 也是六欄位,但增加的是年份,不是秒。

# Spring:秒 分 時 日期 月份 星期
0 0 9 * * MON-FRI

# Quartz:秒 分 時 日期 月份 星期 年份
0 0 9 ? * MON-FRI 2026

表格若超出畫面寬度,可左右捲動。

環境欄位數秒/年份需確認的擴充語法
POSIX cron5皆無基本語法
Cronie5皆無步進值、@ 簡寫
GitHub Actions5皆無步進值;不支援 @ 簡寫
Kubernetes CronJob5皆無步進值、@monthly 等簡寫;? 等同 *
Spring6只有秒L、W、#、?
Quartz6–7秒;年份可省略L、W、#、?
EventBridge Scheduler6只有年份?、L、W、#

EventBridge Scheduler 的順序是「分、時、日期、月份、星期、年份」。其中 ? 表示不指定特定值,用在日期或星期其中一欄。星期日的編號也不同:POSIX 是 0,Cronie 接受 0 與 7,Quartz 與 EventBridge Scheduler 則是 1。移植時不能直接沿用星期編號。

日期與星期的 OR 條件:不是同時符合才執行

在 Vixie Cron/Cronie 系列的比對規則中,日期與星期兩欄若都不是以 * 開頭,只要任一欄符合就會執行。若其中一欄以 * 開頭,包括 */n,則要求兩欄條件都符合。

# 原本想要:只在 13 日且為星期五的 09:00 執行
0 9 13 * 5

# 實際:每月 13 日,或每個星期五的 09:00 都執行

以 2025 年 1 月為例,除了星期一的 13 日,也會在星期五的 3、10、17、24、31 日執行。1-31 與 * 在日期欄位單獨表示相同範圍,搭配限定的星期時,組合規則卻可能不同。應依實作規格判斷,不必推測設計者的意圖。

若要限定「13 日星期五」,可以排定每月 13 日,再由指令檢查星期。排程與指令必須使用相同時區:

# 使用者 crontab:當天是星期五才執行腳本
0 9 13 * * [ "$(date +\%u)" = "5" ] && /path/to/script.sh

date +%u 以 1 表示星期一、5 表示星期五。在 crontab 的指令欄位內,即使寫在引號裡,百分比符號也要以反斜線跳脫。若移到獨立的 shell 腳本,則要移除這個 cron 專用的跳脫字元。

時區與日光節約時間:先確認排程使用哪一個時鐘

傳統 cron 服務預設使用系統本地時區。若工作要求的時區與伺服器設定不同,執行時間就會偏移。

日光節約時間(DST)會造成不存在或重複的當地時間。例如從 02:00 跳到 03:00,當天就沒有 02:30;從 03:00 撥回 02:00,則會出現兩次 02:30。各地的切換時刻不同,這只是時鐘變化的例子,不能直接推論所有排程器都會漏跑或跑兩次。

  • Cronie:cron(8) 說明了少於三小時的時鐘變動補正,適用於固定時刻等符合條件的工作,包括向前調整時補執行、向後調整時避免重複。
  • EventBridge Scheduler:春季跳過不存在的時間,秋季重複的時間只執行一次。
  • GitHub Actions 的 timezone 設定:春季跳過的時段會順延至下一個有效時間。

以 CRON_TZ 指定個別時區時:Cronie 的實作也記載了限制:工作所用時區切換日光節約時間時,可能漏執行或執行兩次。不要把服務預設時區的補正行為,直接套用到另一個時區。請依實作、版本及實際時區驗證;一律避開 02:00–03:00 也不是通用解法。

# 原文的日本時間範例:排程與指令都使用東京時區
CRON_TZ=Asia/Tokyo
TZ=Asia/Tokyo
0 9 * * * /path/to/job.sh

# 另一種設定:排程與指令都使用 UTC
CRON_TZ=UTC
TZ=UTC
0 0 * * * /path/to/midnight-utc-job.sh

CRON_TZ 控制支援此變數的實作如何解讀排程;TZ 則讓 date 等子行程使用同一時區。不是所有 Vixie Cron 衍生版本都支援 CRON_TZ。Kubernetes 應設定 .spec.timeZone,不要把時區變數寫進排程字串。

UTC 適合以 UTC 為基準的工作,可避開該排程的 DST 問題。但對採用 DST 的地區,固定 UTC 時刻無法全年維持相同的當地時間;若需求是當地每天早上 9 點,應使用對應的當地時區。

原文的日本案例使用日本標準時間 JST(UTC+9),日本目前沒有日光節約時間。以 UTC 解讀時,0 0 * * * 對應日本 09:00。GitHub Actions 預設使用 UTC,也支援 IANA timezone 設定;最短排程間隔為 5 分鐘,負載高時可能延遲或省略執行。設定前請查閱官方規格。

執行環境:PATH、shell 與輸出處理

「終端機裡能執行,cron 卻失敗」常與執行環境不同有關。cron 通常不會讀取互動式 shell 的啟動設定。Cronie 會設定 HOME、LOGNAME 等變數,並非完全沒有環境變數;PATH 依實作與設定而定,預設指令 shell 通常是 /bin/sh。

# 容易出錯:依賴 PATH 與目前工作目錄
0 9 * * * python script.py

# 使用執行帳號可存取的絕對路徑
0 9 * * * /usr/bin/python3 /home/user/scripts/script.py

也可以明確設定需要的環境:

PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash
0 9 * * * python3 /home/user/scripts/script.py

寄送電子郵件需要可用的郵件傳送設定。MAILTO 決定輸出內容寄到哪裡,不是單靠結束狀態碼判斷成功或失敗;工作失敗但沒有輸出時,可能不會收到通知。

# 選擇其中一種設定,套用到後續工作
MAILTO=""
# 或將工作輸出寄到此地址
MAILTO=admin@example.com

空字串會停用輸出郵件。若依上述順序同時寫入兩行,後續工作會使用第二個值。

# 將標準輸出與標準錯誤附加到可寫入的日誌
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1

# 丟棄所有輸出,也會失去有用的診斷資訊
0 * * * * /path/to/job.sh > /dev/null 2>&1

確認日誌的寫入權限及輪替設定。依系統不同,可檢查 /var/log/syslog,或使用 journalctl -u cron;服務名稱也可能是 crond。crontab -l 可列出目前使用者的排程。日誌顯示工作已啟動,並不等於指令執行成功。

雲端排程器減少維運工作,但不保證每次都成功

表格若超出畫面寬度,可左右捲動。

服務排程格式常見用途與功能
AWS EventBridge Scheduler六欄位,含年份呼叫目標、重試、死信佇列(DLQ)
Google Cloud Scheduler五欄位 unix-cronHTTP、Pub/Sub、App Engine
GitHub Actions schedule五欄位CI/CD 工作流程
Kubernetes CronJob五欄位Job 與 Pod、並行執行控制

受管排程服務能減少維護排程伺服器的負擔,但無法消除執行目標、權限或網路的故障。監控、警示、重試、並行限制、配額、費用與日誌保存期限,仍須逐項設定與確認。

Kubernetes 也明確說明,某些情況下 CronJob 可能建立兩個 Job,或沒有建立 Job。cron 表達式不保證「恰好成功一次」。工作應盡可能具有冪等性:重複執行不應破壞結果,也不應重複產生原本只應發生一次的外部效果。

單一伺服器的清理、日誌維護等小型工作,若希望減少外部依賴與設定成本,傳統 cron 仍可能是合適的選擇。

五種常見排程錯誤

1. 想每天執行,卻設定成每分鐘

# 每分鐘(以下只列時間欄位)
* * * * *

# 每天午夜
0 0 * * *

星號表示欄位中的所有值。若要指定每天的一個時刻,就要同時限定分鐘與小時。

2. 以為星期日的編號都一樣

POSIX 五欄位語法可用 0 表示星期日;Cronie 也接受 7,但 Quartz 與 EventBridge Scheduler 使用 1。應先確認語法種類,再選擇星期編號。

3. 把「前七天」與「星期一」直接組合

# 錯誤:這是 1–7 日,或每個星期一
0 9 1-7 * 1

# 使用者 crontab:由指令確認是否為星期一
0 9 1-7 * * [ "$(date +\%u)" = "1" ] && /path/to/script.sh

上例才會限定每月第一個星期一;前提是指令與排程使用同一時區。

4. 把步進值當成持續累計的時間間隔

*/30 9-17 * * * 包含 17:30。若要在 17:00 結束,應拆成兩組排程:

0,30 9-16 * * *
0 17 * * *

*/35 * * * * 會選中每小時的 0 分與 35 分,09:35 到 10:00 只隔 25 分鐘。日期欄位的 */2 也會從每月 1 日重新取值,不代表連續每隔 48 小時。

5. 用 31 日代表每個月的最後一天

0 0 31 * * 不會在 2、4、6、9、11 月執行;指定 28–31 日則會在多個日期執行。可在指令中檢查隔天是否為 1 日:

# Cronie 搭配 GNU date;排程與指令皆使用 UTC
CRON_TZ=UTC
TZ=UTC
0 0 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /path/to/script.sh

這會在 UTC 每月最後一天的開始時刻執行。GNU date 的 -d 語法不能直接用於 BSD/macOS 預設的 date;此例採用 UTC 也避開了當地 DST 的影響。若工作依當地營業日曆執行,需另外驗證該時區的日期判斷。

管理 crontab,並確認工作實際完成

保留經過檢查的設定副本

crontab -l > crontab.txt
# 確認匯出成功,檢查內容及機密資訊後才加入版本控制
git add crontab.txt
git commit -m "記錄排程工作"

# 先確認內容:這會取代目前使用者的整份 crontab
crontab crontab.txt

使用註解記錄目的與負責單位:

# [2026-01-15] 資料庫備份;負責單位:維運團隊
0 2 * * * /opt/scripts/db-backup.sh >> /var/log/db-backup.log 2>&1

# [2026-03-01] 每日報表;負責單位:報表團隊
0 8 * * 1-5 /opt/scripts/daily-report.sh >> /var/log/report.log 2>&1

決定輸出目的地、通知規則與保存期限,確認工作帳號能寫入日誌,並管理累積的檔案容量。

用 flock 避免工作重疊

# Linux 的 util-linux flock:已有工作持有鎖定時就跳過
* * * * * /usr/bin/flock -n /home/user/.local/state/myjob/job.lock /path/to/long-job.sh

先建立由工作執行帳號擁有的父目錄,並調整範例路徑。使用期間不要刪除或替換鎖定檔。flock -n 若無法取得鎖定,就立即結束而不等待;它只在持有鎖定期間,協調共用同一把鎖的行程。跨主機或不同檔案系統的行為,必須另外確認。

偵測工作沒有執行的情況

工作完成時向外部監控系統送出訊號,若預期時間內沒收到,就發出警示。Healthchecks.io、Cronitor 提供工作監控服務,也可以自行建立監控 API。訊號應代表你真正關心的完成條件,不能只把「已啟動」當成成功。

用預覽協助檢查,不把預覽當成執行保證

NanToo 的日文版 Cron 表達式產生器支援有限範圍的數字五欄位語法。手動更新預覽後,會以瀏覽器本地時間或 UTC,列出基準時間之後、八年內最多五次符合條件的時間。畫面不會自動更新,也不會安裝或實際排定工作。

工具不支援月份與星期名稱、@ 簡寫、L/W/#/?、秒與年份欄位。預覽也不會模擬正式環境 cron 服務的 DST 補正或重試;最後仍要在實際執行環境確認。

把表達式、時區與執行環境一起確認

五個欄位能簡潔地表達許多定期工作,但共用基本概念不代表所有細節都能直接移植。請把表達式、時區與執行環境視為一組設定。

  • 確認日期與星期是 OR 還是同時符合的條件。
  • 移植時重新檢查欄位數、星期編號與擴充語法。
  • 依業務需求選擇時區,並讓指令中的日期判斷使用同一時區。
  • 確認 PATH、shell、路徑、權限與輸出處理。
  • 將工具預覽與正式環境的規格交叉確認。
  • 準備日誌、避免重疊的機制、重試及漏執行監控。

理解這些邊界,才能減少短短一行 cron 表達式在實際維運中造成的誤設定。

參考資料與來源

編輯說明

本文使用 AI 協助編輯,並於發布前由編輯確認。內容仍可能包含事實、解讀或時效上的錯誤;進行重要判斷前,請查閱所列的一手資料或官方文件。

相關文章