cron 표현식 해석기
cron 표현식을 한국어로 풀고 다음 실행 시각과 launchd plist를 보여 줍니다.
분 시 일 월 요일 · 별칭 @daily, @weekly, @monthly, @yearly, @hourly, @reboot
매주 월·금요일 9시 30분
- 분
30 - 30분
- 시
9 - 9시
- 일
* - 매일
- 월
* - 매월
- 요일
1,5 - 월·금요일
다음 실행 시각
브라우저 시각을 읽는 중입니다.
macOS launchd plist
StartCalendarInterval (dict 2개)
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Weekday</key>
<integer>1</integer>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
<dict>
<key>Weekday</key>
<integer>5</integer>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
</array>- · 목록과 범위는 dict 하나에 담을 수 없어서 dict 2개의 배열로 적었습니다. 배열의 dict 가운데 하나라도 맞으면 실행합니다.
- · 빠진 키는 와일드카드입니다. 예를 들어 Minute을 빼면 그 시간 동안 매분 실행합니다.
- 칸에 표현식을 넣거나 예시 버튼을 누르세요
- 설명, 다음 실행 5번, plist가 바로 나옵니다
- 링크 복사로 같은 결과를 나눌 수 있습니다
자세한 설명
cron 표현식의 다섯 필드와 쓸 수 있는 값
cron 표현식은 분 시 일 월 요일 다섯 칸으로 실행 시각을 적습니다. 예를 들어 30 9 * * 1-5는 평일 9시 30분, */5 * * * *는 5분마다입니다. 이 도구는 표현식을 한국어 설명과 다음 실행 시각 5개, 같은 일정을 macOS LaunchAgent에 쓰는 StartCalendarInterval plist 조각으로 바꿔 보여 줍니다. 해석은 macOS 터미널의 man 5 crontab과 man launchd.plist를 기준으로 했고, 계산은 모두 이 브라우저 안에서 합니다.
| 순서 | 필드 | 값 | 이름 |
|---|---|---|---|
| 1 | 분 | 0~59 | 없음 |
| 2 | 시 | 0~23 | 없음 |
| 3 | 일 | 1~31 | 없음 |
| 4 | 월 | 1~12 | JAN~DEC |
| 5 | 요일 | 0~7 (0과 7은 일요일) | SUN~SAT |
한 필드 안에서는 네 가지를 씁니다. *는 그 필드의 처음부터 끝까지, 쉼표는 목록(1,15), 하이픈은 양 끝을 포함하는 범위(8-11은 8·9·10·11시), 슬래시는 간격입니다. 간격은 범위나 * 뒤에 붙입니다. 0-23/2와 */2는 둘 다 0시부터 2시간마다입니다. 5/15처럼 숫자 하나 뒤에 붙이는 형식은 man 페이지에 없지만 macOS cron은 5-59/15로 읽습니다. 다른 cron과 맞추려면 범위로 적는 편이 안전합니다.
가장 많이 헷갈리는 규칙은 일과 요일입니다. 두 필드를 모두 *가 아닌 값으로 적으면 둘 중 하나만 맞아도 실행합니다. man 페이지의 예인 30 4 1,15 * 5는 매월 1일과 15일, 그리고 매주 금요일 4시 30분에 돕니다. “1일이면서 금요일”이 아닙니다.
월·요일 이름은 영어 세 글자를 대소문자 구분 없이 씁니다. macOS의 man 페이지는 이름을 목록이나 범위에 쓰지 못한다고 적어 두었으니(MON-FRI 대신 1-5) crontab에는 숫자가 안전합니다. 원문은 macOS 터미널의 man 5 crontab, 온라인으로는 같은 계열인 FreeBSD crontab(5)에서 볼 수 있습니다.
자주 쓰는 cron 표현식
| 표현식 | 뜻 |
|---|---|
* * * * * | 1분마다 |
*/5 * * * * | 5분마다 (매시 0, 5, 10 … 55분) |
*/10 * * * * | 10분마다 (매시 0, 10 … 50분) |
0 * * * * | 1시간마다, 매시 정각 (@hourly) |
0 */2 * * * | 2시간마다 정각 (0시, 2시 … 22시) |
0 9 * * * | 매일 9시 |
0 9 * * 1-5 | 평일(월~금요일) 9시 |
0 9 1 * * | 매월 1일 9시 |
0 0 * * 0 | 매주 일요일 0시 (@weekly) |
0 0 1 1 * | 매년 1월 1일 0시 (@yearly) |
*/N은 0분부터 N분 간격이라 60을 나누어떨어지지 않는 수는 간격이 고르지 않습니다. */7 * * * *은 0, 7 … 56분에 돌고, 56분 다음은 4분 뒤인 다음 시각 0분입니다. cron은 분 단위가 가장 작아서 초 단위 실행은 적을 수 없습니다.
29~31일을 적으면 그 날짜가 없는 달은 건너뜁니다. 0 0 31 * *는 1년에 7번만 돌고, 0 0 31 2 *는 한 번도 돌지 않습니다. 표준 cron에는 “말일”을 뜻하는 기호가 없어서, Quartz의 L을 넣으면 이 도구는 오류로 알려 줍니다.
cron을 launchd StartCalendarInterval로 옮길 때
macOS에서는 cron 대신 launchd로 예약 작업을 돌릴 수 있고, Apple은 Scheduling Timed Jobs 문서에서 launchd를 권합니다. cron의 다섯 필드는 StartCalendarInterval의 키 다섯 개와 하나씩 짝이 맞습니다.
| cron 필드 | launchd 키 | 값 |
|---|---|---|
| 분 | Minute | 0~59 |
| 시 | Hour | 0~23 |
| 일 | Day | 1~31 |
| 월 | Month | 1~12 |
| 요일 | Weekday | 0~7 (0과 7은 일요일) |
- 빠진 키는
*와 같습니다.Hour만 적고Minute을 빼면 그 시간 동안 매분 실행하므로, 정각에 한 번 돌리려면Minute0을 꼭 적습니다. - 키 하나에는 정수 하나만 들어갑니다. 목록과 범위는 dict 여러 개의 배열이 되고, 평일 9시(
0 9 * * 1-5)는Weekday1~5의 dict 5개가 됩니다. 조합이 수십 개를 넘으면 이 도구는 plist를 만들지 않고 다른 방법을 권합니다. */5같은 분 간격은StartInterval(초)이 간단합니다. 다만 시계의 0분, 5분에 맞추지 않고 작업을 불러온 때부터 세며, 잠든 동안의 실행은 건너뜁니다.- man 페이지는 한 dict에
Day와Weekday가 함께 있으면 둘 중 하나만 맞아도 실행한다고 적습니다. cron의 일·요일 규칙과 같습니다. 반대로 일이나 요일 필드를*/2처럼*로 시작하면 cron은 그 필드를 제한하지 않은 것으로 보고 두 조건을 모두 만족하는 날에만 실행합니다(macOS cron 소스의DOM_STAR처리). 이 조건은 plist로 옮길 수 없어서 이유를 따로 보여 줍니다.
plist 전체를 쓰고 launchctl로 올리는 절차는 macOS LaunchAgent plist 예제 글에 정리했습니다.
맥이 잠든 사이 지난 실행: cron과 launchd의 차이
man launchd.plist는 이 차이를 직접 적어 둡니다. cron은 컴퓨터가 잠든 동안의 실행을 건너뛰고, launchd의 StartCalendarInterval은 다음에 깨어날 때 실행합니다. 잠든 사이 여러 번이 지났으면 한 번으로 합칩니다. StartInterval은 잠든 동안 돌아온 실행을 놓칩니다. Apple 문서에 따르면 잠든 것이 아니라 전원이 꺼져 있었다면 다음 예약 시각까지 실행하지 않습니다.
저는 맥북 한 대에서 launchd 작업 51개를 돌립니다. 38개는 StartCalendarInterval, 13개는 StartInterval입니다. 20분마다 도는 StartInterval 작업은 덮개를 닫아 둔 저녁에 7시간 가까이 한 번도 돌지 않았고, 깨어난 뒤에도 밀린 실행이 몰려서 돌지 않았습니다. 달력 예약 작업은 깨어난 직후 몇 초 사이에 시작했다가 네트워크가 돌아오기 전이라 DNS를 찾지 못하고 (Errno 8) 실패한 적이 있습니다.
그래서 잠든 사이에 시각이 지나도 한 번은 돌아야 하는 작업은 StartCalendarInterval로, 놓쳐도 되는 폴링은 StartInterval로 둡니다. 네트워크를 쓰는 작업은 시작할 때 DNS부터 확인합니다. 로그와 고친 과정은 LaunchAgent StartCalendarInterval 잠자기 글에 적었습니다.
1분마다, 5분마다, 1시간마다는 cron 표현식으로 어떻게 쓰나요?
1분마다는 * * * * *, 5분마다는 */5 * * * *, 10분마다는 */10 * * * *, 1시간마다는 0 * * * *(@hourly) 입니다. */N은 매시 0분부터 N분 간격이라 5분마다는 0, 5, 10 … 55분에 실행합니다. 1시간마다를 * * * * *로 적으면 1분마다가 되니 주의합니다. cron은 1분보다 짧은 간격을 지원하지 않습니다.
일과 요일을 둘 다 적으면 두 조건을 모두 만족해야 하나요?
아닙니다. 두 필드를 모두 * 가 아닌 값으로 적으면 둘 중 하나만 맞아도 실행합니다. man 5 crontab의 예인 30 4 1,15 * 5는 매월 1일과 15일, 그리고 매주 금요일 4시 30분에 실행합니다.
요일 필드의 0과 7은 무엇이 다른가요?
둘 다 일요일입니다. crontab도 launchd의 Weekday 키도 0과 7을 모두 일요일로 읽습니다. 이 도구는 plist를 만들 때 0으로 적습니다.
다음 실행 시각은 어느 시간대 기준인가요?
이 페이지를 연 브라우저의 시간대 기준입니다. cron은 작업을 돌리는 컴퓨터의 시간대를 따르므로, 서버가 UTC라면 0 9 * * * 는 한국 시간 18시에 실행됩니다. 서버에서 date 명령으로 시간대를 먼저 확인하세요.