cron 표현식 읽는 법

범위, 간격, 목록, 이름, 단축 표기와 함께 cron의 다섯 개 필드를 설명하고, 모두가 걸려 넘어지는 일자와 요일 규칙을 다룹니다.

cron 표현식은 공백으로 구분된 다섯 개의 값이며, 왼쪽부터 분, 시, 일, 월, 요일 순으로 읽습니다. 현재 시각이 모든 필드와 일치할 때 작업이 실행됩니다.

30 4 * * 1
│  │ │ │ │
│  │ │ │ └── day of week (1 = Monday)
│  │ │ └──── month (any)
│  │ └────── day of month (any)
│  └──────── hour (4am)
└─────────── minute (30)

이 표현식은 "매주 월요일 04:30에"라고 읽습니다.

다섯 개의 필드

#필드허용되는 값비고
10에서 59
20에서 2324시간제이며 0은 자정
31에서 31
41에서 12, 또는 JAN에서 DEC
5요일0에서 6, 또는 SUN에서 SAT0은 일요일이며 대부분의 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 또는 @annually0 0 1 1 *1월 1일 자정
@monthly0 0 1 * *매월 1일 자정
@weekly0 0 * * 0일요일 자정
@daily 또는 @midnight0 0 * * *매일 자정
@hourly0 * * * *매시 정각

@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은 시스템이나 사용자의 시간대를 씁니다. 서머타임으로 시계가 옮겨질 때, 건너뛴 시간대에 걸린 작업은 아예 실행되지 않을 수 있고 반복된 시간대에 걸린 작업은 두 번 실행될 수 있으며 구현에 따라 다릅니다. 하루에 한 번 반드시 실행되어야 하는 작업은 그 전환이 일어나는 새벽 시간대를 피해 잡는 것이 가장 안전합니다.

확신이 서지 않으면 표현식을 문장으로 다시 읽어보고, 실제로 실행될 다음 몇 번의 시각을 확인하십시오. 그 날짜들이 설명한 내용과 다르다면 잘못된 것은 읽은 방식이 아니라 표현식입니다.