cron 표현식 읽는 법
cron 표현식은 공백으로 구분된 다섯 개의 값이며, 왼쪽부터 분, 시, 일, 월, 요일 순으로 읽습니다. 현재 시각이 모든 필드와 일치할 때 작업이 실행됩니다.
30 4 * * 1
│ │ │ │ │
│ │ │ │ └── day of week (1 = Monday)
│ │ │ └──── month (any)
│ │ └────── day of month (any)
│ └──────── hour (4am)
└─────────── minute (30)
이 표현식은 "매주 월요일 04:30에"라고 읽습니다.
다섯 개의 필드
| # | 필드 | 허용되는 값 | 비고 |
|---|---|---|---|
| 1 | 분 | 0에서 59 | |
| 2 | 시 | 0에서 23 | 24시간제이며 0은 자정 |
| 3 | 일 | 1에서 31 | |
| 4 | 월 | 1에서 12, 또는 JAN에서 DEC | |
| 5 | 요일 | 0에서 6, 또는 SUN에서 SAT | 0은 일요일이며 대부분의 cron 구현은 7도 받아들입니다 |
일부 스케줄러는 형태가 다릅니다. 많은 Java 소프트웨어가 쓰는 Quartz는 초를 맨 앞에 놓고 연도를 선택적으로 덧붙이며, 요일에 일요일부터 시작하는 1에서 7까지의 번호를 매깁니다. 표현식의 필드가 여섯 개나 일곱 개라면, 읽은 내용을 믿기 전에 어떤 시스템을 위해 쓰인 것인지 확인하십시오.
연산자
네 가지가 있으며, 하나의 필드 안에서 서로 조합할 수 있습니다.
| 기호 | 이름 | 예시 | 의미 |
|---|---|---|---|
* | 임의 | * * * * * | 매일 매분 |
, | 목록 | 0 9,13,17 * * * | 09:00, 13:00, 17:00에 |
- | 범위 | 0 9-17 * * * | 09:00부터 17:00까지 양 끝을 포함해 매시 정각에 |
/ | 간격 | */15 * * * * | :00, :15, :30, :45에 |
간격은 언제나 범위에 적용됩니다. 분 필드의 */15는 "0에서 시작해 59까지 15번째 값마다"라는 뜻입니다. 명시적인 범위에도 간격을 줄 수 있습니다. 5-30/10은 5, 15, 25를 주고, 35는 범위 끝을 넘으므로 거기서 멈춥니다.
간격은 "지금부터 15분마다"라는 뜻이 아니며, 시계 위의 고정된 값들을 고르는 것입니다. */40은 :00과 :40에 실행되고, 그다음에는 다음 시간의 :00까지 20분만 기다립니다. 매시간 계산이 다시 시작되기 때문입니다. 목록 안에 범위와 간격을 넣을 수 있으므로 0 0-6/2,12,18-23 * * *도 유효한 시 필드입니다.
이름과 단축 표기
월과 요일 필드는 세 글자 이름을 받아들이며 대소문자는 상관없으므로 JAN, jan, Jan은 모두 같습니다. 고전적인 crontab 문서는 이름의 범위와 목록은 허용되지 않는다고 하지만, 많은 최신 구현은 MON-FRI도 받아들입니다. 어떤 프로그램이 작업을 실행하는지 확실하지 않다면 숫자를 쓰십시오. 1-5는 어디에서나 모호하지 않습니다.
다섯 개 필드 전체를 대신하는 단축 표기가 여럿 있습니다.
| 단축 표기 | 같은 표현 | 실행 시점 |
|---|---|---|
@yearly 또는 @annually | 0 0 1 1 * | 1월 1일 자정 |
@monthly | 0 0 1 * * | 매월 1일 자정 |
@weekly | 0 0 * * 0 | 일요일 자정 |
@daily 또는 @midnight | 0 0 * * * | 매일 자정 |
@hourly | 0 * * * * | 매시 정각 |
@reboot도 있지만 이것은 일정이 아닙니다. cron 자체가 시작될 때 작업을 한 번 실행합니다.
일 필드와 요일 필드의 함정
바로 이것이 사람들의 발목을 잡습니다. 일 필드와 요일 필드가 모두 제한되어 있을 때, 즉 둘 다 *가 아닐 때, cron은 둘 다 일치할 때가 아니라 둘 중 하나라도 일치할 때 작업을 실행합니다.
0 0 13 * 5
이것을 "13일의 금요일 자정에"라고 읽을 수도 있습니다. 그러나 실제 의미는 "매월 13일 자정, 그리고 매주 금요일 자정에"입니다. 한두 번이 아니라 1년에 60번이 넘게 실행됩니다.
기대했던 AND 동작은 두 필드 중 하나가 *일 때만 적용됩니다. 그래서 0 0 * * 5는 매주 금요일이고 0 0 13 * *는 매월 13일이며, 둘 다 지극히 정상입니다. 둘 다 제한할 때 OR이 켜지는 것입니다.
다섯 개 필드로 "13일의 금요일"을 표현하는 표준적인 방법은 없습니다. 흔한 우회책은 매월 13일로 일정을 잡고, 작업이 실제 일을 하기 전에 요일을 스스로 확인하게 하는 것입니다.
관련된 미묘한 문제가 하나 더 있습니다. 일부 구현은 필드가 문자 그대로 *로 시작하는지를 보고 그 필드가 제한되었는지를 판단합니다. 그런 구현에서는 요일 필드의 0-6이 모든 요일을 포함하는데도 제한된 것으로 취급되어 OR 동작이 조용히 켜집니다. "임의"를 뜻할 때는 *를 쓰십시오.
확인해 볼 만한 실수들
* */2 * * *는 두 시간에 한 번이 아니라 그 시간대의 매분 실행되어 하루에 720번 돌아갑니다. 원하던 것은0 */2 * * *이며 이는 12번입니다.- 분 필드를 빼먹으면 모든 값이 한 칸씩 왼쪽으로 밀리는데도 대개 파싱은 되므로, 완전히 엉뚱한 시각에 도는 유효한 일정이 만들어집니다.
0 0 31 * *는 31일이 없는 달을 조용히 건너뜁니다.- 스케줄러가 시간대를 지정하게 해주지 않는 한 cron은 시스템이나 사용자의 시간대를 씁니다. 서머타임으로 시계가 옮겨질 때, 건너뛴 시간대에 걸린 작업은 아예 실행되지 않을 수 있고 반복된 시간대에 걸린 작업은 두 번 실행될 수 있으며 구현에 따라 다릅니다. 하루에 한 번 반드시 실행되어야 하는 작업은 그 전환이 일어나는 새벽 시간대를 피해 잡는 것이 가장 안전합니다.
확신이 서지 않으면 표현식을 문장으로 다시 읽어보고, 실제로 실행될 다음 몇 번의 시각을 확인하십시오. 그 날짜들이 설명한 내용과 다르다면 잘못된 것은 읽은 방식이 아니라 표현식입니다.