리눅스 cron 사용법 — 예약 작업·crontab
"매일 새벽 3시에 백업해줘", "5분마다 이거 체크해줘" — 사람 손 안 거치고 정해진 때에 명령을 자동 실행하는 게 cron입니다.
19편에서 systemd 서비스로 "프로그램을 항상 떠 있게" 만들었죠. 그런데 어떤 일은 "항상"이 아니라 "정해진 때에 한 번씩"이 맞습니다 — 매일 새벽 백업, 매시간 정리, 5분마다 상태 점검. 그게 cron입니다(우분투에선 cron.service로 떠 있는 데몬). 컴퓨터의 "알람 시계 + 자동 실행" 기능이에요.
이번 편은 — crontab -e로 내 예약 작업을 적고, "분 시 일 월 요일 명령"이라는 cron 시간 문법을 읽고 쓰고, 그리고 입문자가 거의 다 한 번씩 당하는 함정들(왜 cron에서만 안 되지?)을 짚습니다. 26편 입문 시리즈 20편 — 이걸로 "중급" 묶음(13~20편: vim·프로세스·디스크·네트워크·ufw·SSH·systemd·cron)이 끝나고, 다음 21편부터 "고급"(셸 스크립트~도커)입니다. (참고: 요즘은 systemd timer도 같은 일을 하는데, cron이 더 단순하고 어디서나 통해서 입문엔 cron부터.)
crontab은 기본 설치돼 있어요. 8편(nano — crontab 편집기로 씀)·12편(>/dev/null 2>&1 리다이렉션)·19편(systemd·로그)을 봤다면 이어집니다. 실습은 안전한 작업(date >> /tmp/cron-test.log 같은)으로.
cron이 뭔가 — crontab과 cron.d
cron은 "지금 몇 시지? 실행할 예약 작업 있나?"를 매분 확인하는 데몬입니다(systemctl status cron으로 떠 있는 거 확인 가능 — 19편). 예약 작업 목록을 적어두는 곳이 몇 군데 있어요:
crontab -e(사용자별) — 가장 많이 씀. "내(jspark) 권한으로 돌릴 작업들".sudo crontab -e면 root 권한 작업. 사람마다 자기 목록을 가짐./etc/crontab,/etc/cron.d/(시스템) — 시스템 전체 작업. 형식이 살짝 다름(실행할 '사용자' 칸이 하나 더 있음). 패키지가 설치하는 작업들이 여기 들어가기도./etc/cron.daily/,cron.hourly/,cron.weekly/— "여기에 스크립트를 넣어두면 매일/매시간/매주 알아서 실행" (시간을 직접 안 정하고 싶을 때).logrotate같은 게 이렇게 돔.
입문 단계에선 crontab -e 하나면 충분합니다. 나머지는 "이런 것도 있다" 정도.
crontab -e — 내 예약 작업 적기
crontab -e로 열어서 — 맨 위에 SHELL·PATH·MAILTO="" 3줄 적고(함정 예방), 그 아래에 작업을 한 줄씩 추가. 작업 줄은 항상 절대 경로로(~·상대경로 X), 끝에 >> 로그파일 2>&1(출력을 로그로 — 12편). crontab -l로 확인. 백업할 땐 crontab -l > ~/my-crontab-backup.txt 해두면 안심(crontab -r 실수 대비).cron 시간 문법 — 분 시 일 월 요일
작업 줄의 앞 다섯 칸이 "언제"입니다: 분(0-59) 시(0-23) 일(1-31) 월(1-12) 요일(0-7, 0·7=일요일). *는 "매번(모든 값)". 예시로 익히는 게 빠릅니다:
읽는 요령: 왼쪽부터 "몇 분 / 몇 시 / 며칠 / 몇 월 / 무슨 요일". 헷갈리면 crontab.guru에 식을 넣으면 "이건 ~할 때 실행"이라고 영어로 설명해줍니다(번역해서 보면 됨) — cron 식을 쓸 때 거의 항상 켜두는 사이트예요. 주의: '일'과 '요일'을 둘 다 지정하면 둘 중 하나만 맞아도 실행됩니다(AND 아니고 OR) — 헷갈리는 지점이니, 보통 한쪽은 *로 둡니다.
흔한 함정 + 정리
"터미널에선 되는데 cron에 넣으면 안 돼요" — 거의 다 이 셋 중 하나입니다.
- ① PATH가 짧다 — cron은 로그인 셸이 아니라
PATH가/usr/bin:/bin정도뿐. 그래서node·python3·docker같은 게 "command not found"가 됩니다. 해결: 명령을 절대 경로로 쓰거나(/usr/bin/python3 ...—which python3으로 경로 확인), crontab 맨 위에PATH=...를 명시. 스크립트 안에서도 PATH를 설정하면 더 확실. - ② 출력이 어디 갔지? — cron 작업의 출력(stdout·stderr)은 기본적으로 그 사용자에게 로컬 메일로 갑니다(아무도 안 봄, 쌓이기만). 그래서 항상 끝에
>> /경로/작업.log 2>&1(로그 파일에 — 12편) 또는>/dev/null 2>&1(완전 무시 — "이 작업은 출력 안 봐도 됨"). 디버깅 중엔 로그로, 안정되면/dev/null로. - ③ 작업 디렉토리·환경이 다르다 — cron 작업은 홈 디렉토리에서, 최소한의 환경 변수로 실행됩니다. 스크립트가 "현재 폴더"를 가정하면 깨져요. 스크립트 안에서
cd /작업할/경로를 먼저 하거나, 모든 경로를 절대 경로로.%문자는 crontab에서 특수 취급되니\%로 이스케이프.
>> ~/cron-debug.log 2>&1 붙이고 → ② 일단 * * * * *(매분)로 걸어서 1~2분 기다린 뒤 그 로그를 tail -f ~/cron-debug.log(12편)로 보기 → ③ "command not found"면 PATH(절대 경로로 고침), 다른 에러면 그 메시지대로 → ④ 되면 시간 식을 원래대로(매분 → 진짜 주기). 그래도 안 보이면 journalctl -u cron -f(19편)로 cron 자체 로그를 — "작업을 실행했다"는 줄은 거기 뜹니다. 그리고 crontab -r은 절대 습관처럼 치지 말 것 — 다 날아갑니다.crontab -e(편집)·crontab -l(목록)·crontab -r(전부 삭제 — 위험). 맨 위에 SHELL·PATH·MAILTO="" 3줄. 시간: 분 시 일 월 요일 명령, *=매번, */5=5간격, 1-5=범위, 0,30=목록, @daily·@reboot=별칭. 함정 셋: PATH 짧음(절대 경로!), 출력은 메일로(>> log 2>&1 또는 >/dev/null 2>&1), 환경/디렉토리 다름(스크립트 안에서 cd·절대 경로). 디버깅 = 로그 붙이고 매분으로 → tail -f. 식 확인은 crontab.guru.시리즈 흐름
- 1~12편 입문·기초 ✔ 13~19편 중급(vim·프로세스·디스크·네트워크·ufw·SSH·systemd) ✔
- 20편 — cron (이 글) ✔ — "중급" 묶음 완료
- 21편 — 셸 스크립트 작성법 (지금까지의 명령들을 하나로 묶어 자동화 — "고급" 묶음 시작)
- 22편~ — 셸 스크립트 베스트 프랙티스 / sed·awk / 로그 분석 / 서버 보안 / 도커 …
오늘 할 일: crontab -e로 열어서 맨 위에 SHELL·PATH·MAILTO="" 3줄 적고, * * * * * date >> /tmp/cron-test.log 2>&1 한 줄 추가 → 저장 → 1~2분 뒤 cat /tmp/cron-test.log로 매분 시각이 쌓이는지 확인 → crontab -e로 그 줄 지우기. "예약 작업이 진짜 도는구나"를 한 번 보면 됩니다. 21편에서 만나요. (cron 전체는 man 5 crontab·man crontab, 식 확인은 crontab.guru.)
우분투·리눅스 입문 시리즈
"중급" 묶음 완주 — 이제 정해진 때에 일이 자동으로 돌아갑니다. 21편 "셸 스크립트 작성법"으로 "고급" 묶음을 시작합니다.
다음 편은 JUNAI 블로그에서 이어 보세요.