
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–23 | 24 小時制 |
| 日期 | 1–31 | 指一個月中的第幾天;不存在的日期不會符合此條件,但仍須注意與星期的 OR 組合 |
| 月份 | 1–12 | JAN–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:00 | 0 9 * * * |
| 每天 02:00 | 0 2 * * * |
| 星期一至星期五,09:00 至 18:00 的每個整點 | 0 9-18 * * 1-5 |
| 每週一 09:00 | 0 9 * * 1 |
| 每週日 03:00 | 0 3 * * 0 |
| 每月 1 日午夜 | 0 0 1 * * |
| 每月 1 日與 15 日 09:00 | 0 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 提供以下簡寫,用來取代時間欄位:
表格若超出畫面寬度,可左右捲動。
| 簡寫 | 對應排程或行為 |
|---|---|
@yearly | 0 0 1 1 * |
@monthly | 0 0 1 * * |
@weekly | 0 0 * * 0 |
@daily | 0 0 * * * |
@hourly | 0 * * * * |
@reboot | 系統啟動後執行一次;Cronie 通常不會因為單純重新啟動 cron 服務而再次執行 |
Cronie 透過鎖定檔避免重複執行啟動工作。不要把 @reboot 當成服務重新啟動時的觸發機制;換用其他 cron 實作時,也要確認啟動條件。
Spring 在最前面加入秒欄位;Quartz 有六個必要欄位,最後可選填年份。EventBridge Scheduler 也是六欄位,但增加的是年份,不是秒。
# Spring:秒 分 時 日期 月份 星期
0 0 9 * * MON-FRI
# Quartz:秒 分 時 日期 月份 星期 年份
0 0 9 ? * MON-FRI 2026
表格若超出畫面寬度,可左右捲動。
| 環境 | 欄位數 | 秒/年份 | 需確認的擴充語法 |
|---|---|---|---|
| POSIX cron | 5 | 皆無 | 基本語法 |
| Cronie | 5 | 皆無 | 步進值、@ 簡寫 |
| GitHub Actions | 5 | 皆無 | 步進值;不支援 @ 簡寫 |
| Kubernetes CronJob | 5 | 皆無 | 步進值、@monthly 等簡寫;? 等同 * |
| Spring | 6 | 只有秒 | L、W、#、? |
| Quartz | 6–7 | 秒;年份可省略 | L、W、#、? |
| EventBridge Scheduler | 6 | 只有年份 | ?、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-cron | HTTP、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 表達式在實際維運中造成的誤設定。
參考資料與來源
- Cronie implementation: startup and per-job time zones ↗
- Google Cloud Scheduler: cron format ↗
- POSIX crontab ↗
- Cronie crontab(5) ↗
- Cronie cron(8): clock changes ↗
- GitHub Actions: schedule ↗
- Kubernetes CronJob ↗
- EventBridge Scheduler schedule types ↗
- Spring scheduling ↗
- Quartz CronTrigger ↗
- GNU date: relative items ↗
- util-linux flock ↗
編輯說明
本文使用 AI 協助編輯,並於發布前由編輯確認。內容仍可能包含事實、解讀或時效上的錯誤;進行重要判斷前,請查閱所列的一手資料或官方文件。

