사용 가이드게시일 읽는 시간 약 11분

cron이 실행되지 않는 원인 체크리스트: 직접 하면 되는데 cron에서 실패하는 이유와 로그 확인법

crontab에 분명히 써 둔 배치가 실행되지 않는다. 터미널에서 직접 실행하면 성공하는데 cron에서는 아무 일도 일어나지 않는다. cron 문제는 어디에도 오류가 표시되지 않은 채 조용히 실패하는 경우가 많아 원인을 찾는 데 시간이 걸리기 쉽습니다. 이 글에서는 cron이 실행되지 않을 때 확인할 순서를 "식", "cron 본체", "로그", "실행 환경", "파일과 권한", "시간대"로 나눠 정리하고, 직접 하면 되는데 cron에서는 실패하는 전형적인 이유와 고치는 방법을 정리합니다.

먼저 구분하기: "cron이 실행하지 않는" 것인가, "명령이 실패하는" 것인가

"cron이 안 돈다"고 해도 원인은 크게 두 가지로 나뉩니다. 하나는 애초에 cron이 그 시각에 명령을 시작하지 않는 경우, 다른 하나는 cron은 예정대로 시작했는데 명령 안에서 실패하는 경우입니다. 어느 쪽이냐에 따라 조사할 곳이 완전히 다르므로 먼저 구분합니다.

  1. 1

    로그에 시작 기록이 있는지 본다

    뒤에서 설명하는 cron 로그에 그 시각 "CMD (명령)" 줄이 있으면 cron은 시작한 것이고 원인은 명령 쪽입니다. 줄이 없으면 식, cron 본체, 파일 작성법을 의심합니다.

  2. 2

    1분마다 도는 테스트 줄을 추가해 본다

    crontab -e로 "* * * * * date >> /tmp/cron-test.log 2>&1"을 임시로 추가하고 1~2분 기다린 뒤 /tmp/cron-test.log에 시각이 늘어나는지 봅니다. 늘어나면 cron 자체는 정상입니다. 확인이 끝나면 반드시 삭제합니다.

  3. 3

    실제 줄의 시각을 가까운 시각으로 바꿔 시험한다

    매일이나 매주 실행하는 일정은 다음 실행까지 기다리면 며칠이 걸립니다. 테스트하는 동안만 시각을 몇 분 뒤로 바꾸고 결과를 본 뒤 원래대로 돌리면 바로 확인할 수 있습니다.

식을 잘못 써서 "실행되지 않는" 것처럼 보이는 경우

cron은 식이 형식상 올바르면 의도와 달라도 불평 없이 그 시각에 실행합니다. "안 돈다"고 생각했는데 사실은 예상치 못한 일시에 돌고 있었던 경우도 적지 않습니다. 먼저 식 자체를 의심하세요.

쓴 식의도실제 동작
0 9 31 * *매월 말일31일이 없는 2·4·6·9·11월에는 실행되지 않음
0 9 30 2 *2월 말일2월 30일은 존재하지 않으므로 한 번도 실행되지 않음
0 9 1-7 * 1첫째 월요일매주 월요일과 매월 1~7일에 실행(OR)
30 9 * * *(UTC 서버)일본 시간 9:30일본 시간 18:30에 실행
9 30 * * *9:30시 필드에 30은 쓸 수 없어 오류로 읽히지 않음
* 3 * * *매일 3시에 한 번3:00~3:59 매분, 60번 실행

날짜와 요일의 조합이나 월말 작성법은 특히 틀리기 쉬워서 cron의 날짜·요일 OR 규칙과 n번째 요일·월말 작성법에서 자세히 설명합니다. cron 식 검사기에 crontab 줄을 붙여 넣으면 의미를 해석해 주고 다음 실행 일시를 10개 나열하므로 "언제 실행될 예정인지"를 바로 확인할 수 있습니다.

cron 본체 상태와 로그 확인 방법

식이 맞는데 시작 기록이 없다면 cron 서비스가 멈추지 않았는지, 로그에 오류가 나오지 않았는지 확인합니다. 배포판마다 서비스 이름과 로그 위치가 다릅니다.

확인할 것Ubuntu·DebianRHEL·CentOS·Rocky·Amazon Linux
서비스 상태systemctl status cronsystemctl status crond
서비스 시작sudo systemctl enable --now cronsudo systemctl enable --now crond
로그(파일)grep CRON /var/log/syslogsudo cat /var/log/cron
로그(journal)journalctl -u cron --since todayjournalctl -u crond --since today
  • "(사용자명) CMD (명령)" 줄: 그 시각에 명령을 시작했다는 기록. 이것이 있으면 cron은 정상
  • "(CRON) info (No MTA installed, discarding output)": 명령이 뭔가를 출력했지만 메일로 보낼 수단이 없어서 버렸다는 뜻. 오류 메시지가 여기서 사라졌을 가능성이 높다
  • "(*system*) … WRONG FILE OWNER" "INSECURE MODE": /etc/cron.d 등에 있는 파일의 소유자나 권한이 이상해서 읽히지 않고 있다
  • "bad minute" "bad hour" "errors in crontab file": 식의 형식 오류. 그 줄은 읽히지 않는다

직접 하면 되는데 cron에서는 실패하는 5가지 이유

로그에 시작 기록이 있는데 결과가 나오지 않았다면 명령이 cron 환경에서 실패하고 있는 것입니다. cron은 로그인했을 때의 셸과는 다른, 아주 최소한의 환경에서 명령을 실행합니다. 직접 해 보면 성공하는데 cron에서는 실패하는 것은 대부분 이 차이 때문입니다.

원인증상고치는 법
PATH가 짧다command not found(/usr/local/bin이나 ~/.local/bin의 명령)명령을 절대 경로로 쓴다. 또는 crontab 맨 앞에 PATH=를 쓴다
셸이 /bin/shbash 문법(source, [[ ]], 배열)에서 오류스크립트 첫 줄에 #!/bin/bash를 쓰고 스크립트로 호출한다
.bashrc 등을 읽지 않는다환경 변수(API 키나 언어 버전 관리)가 비어 있다필요한 변수를 스크립트 안에서 설정하거나 crontab 맨 앞에 쓴다
작업 디렉터리가 홈상대 경로 파일을 찾지 못한다스크립트 처음에 cd /path/to/dir 하거나 절대 경로로 한다
%가 줄바꿈이 된다date +%Y%m%d 도중에 명령이 끊긴다crontab 안에서는 \%로 이스케이프한다

cron과 같은 환경에서 시험하려면 "env -i HOME=$HOME PATH=/usr/bin:/bin SHELL=/bin/sh /bin/sh -c '명령'"처럼 환경 변수를 거의 비운 상태로 명령을 실행해 보는 것이 지름길입니다. 여기서 실패하면 원인이 환경 차이라는 것을 알 수 있습니다.

% 문제는 알아차리기 어려우므로 특히 주의해야 합니다. crontab 명령 부분에서 %는 "여기서 줄바꿈, 나머지는 표준 입력으로 넘김"이라는 뜻이 됩니다. "tar czf /backup/$(date +%Y%m%d).tar.gz /data" 같은 줄은 % 앞에서 명령이 끊겨 실패합니다. "date +\%Y\%m\%d"로 이스케이프하거나, 처리를 셸 스크립트로 정리하고 crontab에서는 스크립트를 호출하기만 하면 확실합니다.

파일·권한·줄바꿈 코드의 함정

crontab 작성법 자체는 맞더라도 파일 위치나 권한 때문에 읽히지 않거나 실행되지 않는 경우도 있습니다. 다음 항목을 차례로 확인합니다.

  • 스크립트에 실행 권한이 있는가: ls -l로 x가 붙어 있는지 확인하고, 없으면 chmod +x script.sh. 또는 sh script.sh처럼 셸을 거쳐 호출한다
  • 첫 줄의 #!가 올바른가: #!/bin/bash의 경로가 실제로 있는가. Windows에서 편집한 파일은 줄 끝이 CRLF가 되어 "/bin/bash^M: bad interpreter"로 실패하므로 dos2unix 등으로 LF로 바꾼다
  • crontab 마지막 줄 뒤에 줄바꿈이 있는가: 마지막 줄에 줄바꿈이 없으면 그 줄을 무시하는 구현이 있다
  • /etc/cron.d 파일에 사용자명 필드가 있는가: /etc/crontab과 /etc/cron.d/의 파일은 "분 시 일 월 요일 사용자명 명령" 7개 이상의 필드가 필요하다
  • /etc/cron.d의 파일명과 권한: Debian·Ubuntu에서는 파일명에 .이 들어간 파일(backup.cron 등)은 읽히지 않는다. 소유자는 root, 다른 사용자가 쓸 수 없는 권한(644)으로 한다
  • cron.allow·cron.deny: /etc/cron.allow가 있으면 거기에 적힌 사용자만 crontab을 쓸 수 있다

시간대 어긋남: 9시간 어긋나서 실행되고 있지 않은가

"안 돈다"의 정체가 "9시간 어긋나서 돌고 있었다"인 경우가 흔합니다. cron은 cron이 실행되는 서버(컨테이너)의 시간대로 시각을 읽습니다. 클라우드 서버나 컨테이너 이미지는 기본값이 UTC인 경우가 많아, 한국·일본 시간이라고 생각하고 쓴 시각보다 9시간 늦게 실행됩니다.

  1. 1

    서버의 시간대를 확인한다

    date나 timedatectl을 실행해 표시가 JST(한국이라면 KST)인지 UTC인지 봅니다. UTC라면 9시간을 뺀 시각으로 쓰거나 시간대를 바꿉니다.

  2. 2

    시간대를 바꿨다면 cron을 재시작한다

    sudo timedatectl set-timezone Asia/Tokyo(한국은 Asia/Seoul)로 바꿀 수 있지만, 이미 동작 중인 cron은 예전 시간대 그대로인 경우가 있습니다. sudo systemctl restart cron(RHEL 계열은 crond)으로 재시작합니다.

  3. 3

    한 줄만 다른 시간대로 하고 싶을 때

    RHEL 계열에서 쓰이는 cronie는 crontab에 CRON_TZ=Asia/Tokyo라고 쓰면 그 뒤의 줄을 지정한 시간대로 읽습니다. 단, Debian·Ubuntu의 표준 cron에서는 통하지 않으므로 시각을 UTC로 바꿔 쓰는 편이 확실합니다.

GitHub Actions·AWS EventBridge·Kubernetes 등 서버 밖에서 cron 식을 읽는 시스템에서도 같은 어긋남이 생깁니다. GitHub Actions는 항상 UTC이므로 GitHub Actions cron을 일본 시간으로 실행하는 방법을, EventBridge는 EventBridge cron 식 작성법을 참고하세요.

다음에 실패하면 바로 알 수 있게 해 두기

원인을 찾아 고쳤다면 다음에 같은 일이 생겼을 때 바로 알아챌 수 있게 해 두면 문제 조사 시간이 크게 줄어듭니다.

  • 출력을 반드시 로그로 남긴다: 줄 끝에 >> /var/log/myjob.log 2>&1을 붙여 오류까지 이어 쓰기로 기록한다. 로그가 너무 커지지 않도록 logrotate도 설정한다
  • MAILTO를 설정한다: crontab 맨 앞에 MAILTO=you@example.com이라고 쓰면 출력이 있을 때 메일로 온다(서버에 메일을 보낼 수단이 필요)
  • 중복 실행을 막는다: 지난번 처리가 끝나기 전에 다음 처리가 시작되면 문제의 원인이 된다. flock -n /tmp/myjob.lock 명령처럼 잠금을 건다
  • 성공 여부를 밖에서 감시한다: 처리 마지막에 모니터링 서비스의 URL을 호출하는 "하트비트 감시"를 넣으면 실행되지 않은 것도 알아챌 수 있다
  • crontab 백업: crontab -l > ~/crontab.bak을 정기적으로 실행해 설정 변경 이력을 남긴다

crontab 작성법이나 기호의 의미를 다시 정리하고 싶을 때는 crontab 작성법과 빠른 참조표가 도움이 됩니다. 설정을 바꿀 때마다 cron 식 검사기로 다음 실행 일시를 확인해 두면 "생각한 것과 다른 시각에 실행되는" 유형의 문제는 미리 막을 수 있습니다.

자주 묻는 질문

crontab에 썼는데 실행되지 않을 때 먼저 무엇을 확인해야 하나요?
먼저 cron 로그(Ubuntu라면 grep CRON /var/log/syslog, RHEL 계열이라면 /var/log/cron)를 보고 그 시각에 CMD 줄이 있는지 확인합니다. 줄이 있으면 명령 쪽 실패, 없으면 식 작성 실수나 cron 서비스 정지를 의심합니다. "* * * * * date >> /tmp/cron-test.log"을 임시로 추가하면 cron 자체가 동작하는지 바로 확인할 수 있습니다.
직접 하면 되는데 cron에서는 안 되는 이유는?
cron은 PATH가 /usr/bin:/bin 정도뿐인 최소한의 환경에서 /bin/sh를 쓰고 .bashrc 등도 읽지 않은 채 명령을 실행하기 때문입니다. 명령을 절대 경로로 쓰고, 필요한 환경 변수를 스크립트 안에서 설정하고, 작업 디렉터리로 cd하고, %를 \%로 이스케이프하는 등의 대응으로 대부분 해결됩니다.
cron 로그는 어디서 확인할 수 있나요?
Ubuntu·Debian에서는 /var/log/syslog에 기록되므로 grep CRON /var/log/syslog로 걸러 봅니다. RHEL·CentOS·Rocky Linux 등에서는 /var/log/cron입니다. systemd 환경이라면 journalctl -u cron(RHEL 계열은 -u crond)으로도 확인할 수 있습니다.
cron 실행 시각이 9시간 어긋나는 이유는?
cron이 서버의 시간대로 시각을 읽는데 그 서버가 UTC로 설정되어 있기 때문입니다. 일본 시간과 한국 시간은 UTC보다 9시간 빠르므로, 그 시간이라고 생각하고 쓴 시각보다 9시간 늦게 실행됩니다. 시간대를 Asia/Tokyo(또는 Asia/Seoul)로 바꾸고 cron을 재시작하거나, UTC 시각으로 바꿔 씁니다.
/etc/cron.d에 둔 파일이 실행되지 않습니다.
/etc/cron.d의 파일은 5개 시각 필드와 명령 사이에 실행할 사용자명 필드가 필요합니다. 또한 Debian·Ubuntu에서는 파일명에 .이 들어가면 읽히지 않고, 소유자가 root가 아니거나 다른 사용자가 쓸 수 있는 권한이어도 무시됩니다. 로그의 WRONG FILE OWNER나 INSECURE MODE 표시도 확인하세요.

이 글에서 소개한 도구

함께 읽으면 좋은 글

사용 가이드약 10분

GitHub Actions cron을 일본 시간으로 실행하기: UTC 변환표와 요일 밀림·지연 대책

GitHub Actions의 schedule에 "0 9 * * 1-5"라고 썼는데 워크플로가 일본 시간 오후 6시에 실행됐다면, 오타가 아니라 GitHub Actions의 cron이 항상 UTC(협정 세계시)로 해석되기 때문입니다. 이 글에서는 일본 시간(JST)을 UTC cron 식으로 바꾸는 계산과 변환표, 오전 0~8시를 지정할 때 생기는 "요일·날짜가 전날로 밀리는" 문제, 한 줄로 쓸 수 없을 때 두 줄로 나누는 방법, schedule이 늦거나 실행되지 않을 때의 원인과 대책을 정리합니다. 한국 표준시(KST)도 UTC+9라서 같은 표를 그대로 쓸 수 있습니다.

글 읽기 →
사용 가이드약 10분

crontab 작성법과 빠른 참조표: 5개 필드와 기호의 의미, 자주 쓰는 예, 등록 명령

"매일 3시에 백업", "5분마다 모니터링 스크립트" 같은 정기 실행은 Linux에서는 crontab에 한 줄만 쓰면 설정할 수 있습니다. 하지만 "분 시 일 월 요일" 5개 필드와 * , - / 기호의 조합은 익숙해지기 전까지 잘못 읽기 쉬워서, 1시간에 60번 실행되거나 7분마다 돌리려던 것이 4분 간격이 되는 사고도 자주 일어납니다. 이 글에서는 crontab 작성법의 기본과 기호의 의미, 그대로 쓸 수 있는 빠른 참조표, crontab -e·-l·-r 사용법, 명령 부분을 쓸 때의 주의점을 예시 중심으로 설명합니다.

글 읽기 →
원리 해설약 10분

cron의 날짜와 요일은 OR: 둘째 월요일·월말·마지막 금요일·격주를 올바르게 쓰는 법

"매월 첫째 월요일 9시"라는 생각으로 "0 9 1-7 * 1"이라고 썼더니 매주 월요일에 더해 매월 1~7일 매일에도 실행됐다. cron에서 아주 흔한 이 실수는 날짜와 요일을 둘 다 지정하면 "둘 중 하나"에 해당하는 날에 실행된다는 cron 특유의 규칙 때문입니다. 이 글에서는 날짜와 요일이 OR이 되는 원리와 예외, crontab에서 n번째 요일·월말·마지막 금요일·격주를 올바르게 실행하는 방법, AWS EventBridge와 Spring에서 쓸 수 있는 L·#·W 표기까지 실제 실행 날짜 예시와 함께 설명합니다.

글 읽기 →