알아두면 좋은 내용
cron 5필드 구조
표준 cron은 공백으로 구분된 5개 필드로 시각을 표현합니다. 왼쪽부터 분·시·일·월·요일 순서입니다.
0 9 * * 1-5 = 분 0, 시 9, 일 매일, 월 매월, 요일 월~금 → 평일 오전 9시. 초(second) 필드는 표준 cron에 없습니다(6필드는 Quartz·일부 라이브러리 확장). 요일 7(=일요일)은 Vixie·cronie 등 리눅스 cron의 확장이고, POSIX 규격은 0-6(0=일)만 정의합니다.특수문자 (* / , -) 의미
| 기호 | 의미 | 예시 |
|---|---|---|
| * | 해당 필드의 모든 값 | 시 칸의 * = 매시 |
| */n | n 단위마다 (스텝) | */15 (분) = 0,15,30,45분 |
| a-b | a부터 b까지 범위 | 1-5 (요일) = 월~금 |
| a,b,c | 여러 값 나열 (리스트) | 0,30 (분) = 정각·30분 |
| a-b/n | 범위 안에서 n 단위마다 | 9-18/3 (시) = 9,12,15,18시 |
L(말일)·W(가까운 평일)·#(N번째 요일)·?는 표준 cron에는 없고 Quartz 등 일부 구현에만 있습니다. 이 도구는 표준 5필드(* / , -)만 처리합니다.요일·월 별칭과 @-축약
자주 쓰는 주기는 @ 별칭으로 줄여 쓸 수 있습니다. 이 도구는 입력 시 자동으로 5필드로 풀어 해석합니다.
@hourly
0 * * * *
매시 정각
@daily
0 0 * * *
매일 자정 (=@midnight)
@weekly
0 0 * * 0
매주 일요일 0시
@monthly
0 0 1 * *
매월 1일 0시
@yearly
0 0 1 1 *
매년 1/1 0시 (=@annually)
@reboot
—
부팅 시 1회 (시각 계산 불가)
MON·SUN 같은 영문 약어와JAN~DEC 월 약어는 일부 구현만 지원하므로, 호환을 위해 숫자 사용을 권장합니다. 이 도구는 해석할 때 영문 약어도 숫자로 바꿔 읽습니다.일과 요일 동시 지정 시 OR 규칙
일(3번째)과 요일(5번째)을 둘 다 *로 시작하지 않는 값으로 지정하면, 표준 cron은 두 조건을 OR로 묶습니다 — 둘 중 하나라도 맞으면 실행합니다. 반대로 한쪽이 */2처럼 *로 시작하면 Vixie·cronie는 그 칸을 ‘제한 없음’으로 보고 AND로 판정하며, 이 도구도 같은 규칙을 따릅니다(구현마다 다를 수 있음).
*로 두세요.요일을 다시 확인해 빠져나가는 방식이 일반적입니다.Quartz·클라우드와 다른 점
| 환경 | 필드 수 | 요일 범위 | 특이점 |
|---|---|---|---|
| 표준 cron (이 도구) | 5 | 0-7 (0·7=일, 7은 Vixie·cronie 확장 — POSIX는 0-6) | 일·요일 OR, 초 없음 |
| Quartz (Java) | 6~7 | 1-7 (1=일) | 초 필수, L·W·# 지원, 일·요일에 ? 필요 |
| Spring @Scheduled | 6 | 0-7 (0·7=일) | 맨 앞에 초 필드 추가, Spring 5.3+는 L·W·# 지원 |
| AWS EventBridge 규칙 | 6 | 1-7 (1=일) | 초 없음·끝에 연도 필드, 일·요일 중 하나는 ?, 항상 UTC |
| Kubernetes CronJob | 5 | 0-6 (7 불가) | 시간대는 kube-controller-manager 기준(관리형은 대개 UTC), 1.27+ spec.timeZone 지정 가능 |
1-5 월~금 → 2-6), Kubernetes는 7을 일요일로 받지 않으므로 0을 쓰세요. 또 클라우드 스케줄러는 보통 UTC 기준이라 KST 시각을 그대로 적으면 9시간 늦게 실행됩니다 — 아래 표 참고.KST 시각을 UTC 스케줄러에 옮기는 법
한국 표준시(KST)는 UTC+9이고 서머타임이 없어 늘 9시간을 빼면 됩니다. 함정은 오전 9시 이전입니다 — UTC로는 전날이 되므로 요일도 하루 앞당겨야 합니다. 아래 표는 표준 5필드 기준으로 환산한 값으로, Kubernetes(컨트롤러가 UTC일 때)·GitHub Actions 같은 UTC 스케줄러에 그대로 쓸 수 있습니다.
| 원하는 실행 (KST) | KST 표현식 | UTC 표현식 | 비고 |
|---|---|---|---|
| 매일 오전 9시 | 0 9 * * * | 0 0 * * * | 같은 날 — 시만 9 빼기 |
| 평일 오전 9시 | 0 9 * * 1-5 | 0 0 * * 1-5 | 같은 날 — 시만 9 빼기 |
| 평일 오전 8시 30분 | 30 8 * * 1-5 | 30 23 * * 0-4 | UTC로는 전날 — 요일 숫자를 하루 당김 |
| 매주 월요일 오전 7시 | 0 7 * * 1 | 0 22 * * 0 | UTC로는 전날 — 요일 숫자를 하루 당김 |
| 매일 자정 | 0 0 * * * | 0 15 * * * | UTC로는 전날 — 요일·일 제한이 없어 시만 바꾸면 됨 |
| 매월 1일 오전 3시 | 0 3 1 * * | 표현 불가 | UTC로는 전달 말일 18시 — 표준 cron엔 말일(L)이 없어 28-31일 트리거 + 날짜 조건이 필요. EventBridge는 cron(0 18 L * ? *)로 가능 |
spec.timeZone: Asia/Seoul을 지정하는 편이 실수가 적고, EventBridge Scheduler(규칙이 아닌 스케줄러)도 시간대를 직접 고를 수 있습니다. 반대로 서버 crontab은 그 서버의 시스템 시간대를 따르므로timedatectl로 시간대부터 확인하세요.crontab 등록과 디버깅 — cron에서만 안 될 때
리눅스에서는 crontab -e로 편집기를 열어 한 줄 추가하고 저장하면 즉시 등록됩니다.crontab -l로 목록을 확인하고, crontab -r은 확인 질문 없이 전체 삭제되므로 주의하세요. ‘터미널에서 직접 실행하면 되는데 cron에서만 안 된다’면 대부분 환경변수 차이가 원인입니다 — cron은 로그인 셸이 아니라 SHELL=/bin/sh, PATH=/usr/bin:/bin의 최소 환경으로 명령을 실행합니다(crontab(5) 기준).
| 증상 | 원인 | 해결 |
|---|---|---|
| command not found | PATH가 /usr/bin:/bin뿐이라 /usr/local/bin 등을 못 찾음 | 명령을 절대경로로 쓰거나 crontab 상단에 PATH= 선언 |
| 수동 실행은 OK, cron만 실패 | 비로그인 sh 실행이라 ~/.bashrc의 변수·alias 미적용 | 필요한 환경변수를 crontab이나 스크립트 안에 직접 선언 |
| date +%d 뒤 명령이 잘림 | %는 crontab에서 개행으로 해석, 이후는 표준입력으로 전달 | \%로 이스케이프하거나 스크립트 파일로 분리 |
| 실행됐는지 흔적이 없음 | 출력이 파일이 아닌 메일로만 감 | 명령 뒤에 >> /var/log/작업.log 2>&1 리다이렉트 |
MAILTO=me@example.com을 적으면 수신 주소를 지정하고, MAILTO=""는 메일 발송을 끕니다. 실행 여부 자체는 grep CRON /var/log/syslog(데비안·우분투)나journalctl -u cron(RHEL 계열은 crond)으로 확인할 수 있습니다.한 줄로 안 되는 주기 — 실무 레시피
‘매월 마지막 날’이나 ‘2주마다’는 표준 5필드 문법만으로 표현할 수 없습니다. 이럴 땐 트리거를 조금 넓게 걸어 두고, 명령 앞에서 날짜 조건을 확인해 아니면 빠져나가는 패턴을 씁니다(GNU date 기준).
| 원하는 주기 | 표현식 | 조건·비고 |
|---|---|---|
| 매월 마지막 날 0시 | 0 0 28-31 * * | [ "$(date -d tomorrow +\%d)" = "01" ] && 명령 — 표준 cron엔 L(말일)이 없어 "내일이 1일인지"로 판별 |
| 2주마다 월요일 9시 | 0 9 * * 1 | [ $(( $(date +\%V) % 2 )) -eq 1 ] && 명령 — ISO 주차 홀짝 체크. 53주가 있는 해의 연말·연초엔 한 번 어긋날 수 있음 |
| 업무시간만 10분마다 | */10 9-17 * * 1-5 | */10 9-18로 쓰면 18:50까지 돌아감 — 18시 정각에 끝내려면 0 18 * * 1-5 한 줄 추가 |
| 격월(홀수 달) 1일 | 0 0 1 1-11/2 * | 1·3·5·7·9·11월 — 범위+스텝 문법으로 한 줄 해결 가능 |
| 매월 첫째 월요일 | 0 9 * * 1 | [ $(date +\%d) -le 7 ] && 명령 — 0 9 1-7 * 1은 OR 규칙 탓에 1~7일 전부에도 실행되므로 금물 |
\%는 crontab 한 줄에 인라인으로 넣을 때의 이스케이프이며, 별도 스크립트 파일 안에서는 그냥 %를 씁니다. macOS·BSD의 date는 -d tomorrow 대신date -v+1d를 사용합니다. 조건이 두 개 이상 겹치면 crontab 한 줄에 욱여넣지 말고 스크립트로 빼는 편이 읽기도, 로그 남기기도 쉽습니다.자주 묻는 질문
크론 표현식 읽는 법은?
30 14 * * 1은 분=30, 시=14, 일=*(매일), 월=*(매월), 요일=1(월요일) → 매주 월요일 14시 30분입니다. *는 "모든 값", */5는 "5단위마다", 1-5는 "1부터 5까지", 1,15는 "1과 15"를 뜻합니다.매일 특정 시간에 실행하는 크론은?
*로 둡니다. 매일 오전 9시는 0 9 * * *, 매일 자정은 0 0 * * *, 매일 오후 6시 30분은 30 18 * * *입니다. 시는 0~23(24시간제)으로 적습니다. 오후 2시는 14, 밤 11시는 23입니다.평일에만 실행하려면 어떻게 하나요?
1-5(월~금)를 넣습니다. 평일 오전 9시는 0 9 * * 1-5입니다. 요일은 0=일요일, 1=월요일 … 6=토요일이며, 주말만 실행하려면 0,6을 씁니다. 토요일·일요일 출근일 같은 예외는 cron 한 줄로 표현하기 어려워, 보통 스크립트 안에서 공휴일을 추가로 걸러냅니다.0 0 * * *는 무슨 뜻인가요?
* → 매일 자정(00:00)에 1회 실행입니다. 흔히 일일 배치·백업·로그 정리에 씁니다. 비슷하게 0 * * * *는 매시 정각, * * * * *는 매분 실행입니다. @daily 별칭도 같은 의미입니다.요일에서 0과 7의 차이는?
0 0 * * 0과 0 0 * * 7은 동일하게 매주 일요일 자정이며, 이 도구도 입력의 7을 내부적으로 0으로 바꿔 처리합니다. 다만 POSIX 규격은 0~6(0=일)만 정의하고 Kubernetes CronJob 문서도 0~6으로 안내하므로, 여러 환경에서 쓸 표현식이라면 0을 쓰는 편이 안전합니다.일과 요일을 동시에 지정하면 어떻게 되나요?
0 0 13 * 5는 "매월 13일" 또는 "매주 금요일"에 실행되어, 13일의 금요일뿐 아니라 모든 13일과 모든 금요일에 돌아갑니다. 한쪽만 제한하려면 다른 칸을 *로 두면 됩니다. AND를 원하면 cron 한 줄로는 불가능해 스크립트 쪽에서 날짜를 다시 확인해야 합니다.참고 자료
- crontab(5) 매뉴얼(새 창)man7.org
- POSIX crontab(새 창)pubs.opengroup.org
- Kubernetes CronJob(새 창)kubernetes.io
- AWS EventBridge 일정 표현식(새 창)docs.aws.amazon.com
- 계산 기준
- 표준 cron 5필드(Vixie·cronie crontab(5)) · Kubernetes CronJob·AWS EventBridge 공식 문서의 필드·요일 규칙
- 오류 제보
- 결과가 다르면 contact@youtil.kr로 입력 조건을 알려 주세요. 평일 기준 1~3일 안에 답변합니다.