[linux] 서버 로그 자동 삭제 쉘스크립트 생성 예제 및 크론탭(crontab) 등록 예제
톰켓 was 서버에서 톰켓 로그가
/usr/local/logs/test_api/ 폴더에 아래와 같은 형식으로 쌓인다.
test-api-dev.log.2025-11-01.0.gz
test-api-dev.log.2025-11-01.1.gz
test-api-dev.log.2025-11-01.2.gz
test-api-dev.log.2025-11-02.0.gz
test-api-dev.log.2025-11-03.0.gz
계속 쌓이면 서버 용량을 많이 먹어서 주기적으로 삭제해야한다.
crontab에 등록할 수 있게 만들어보자
조건은 오늘 날짜 기준으로 15일 이전 파일은 모두 삭제하는 것이다.
요구사항을 정리하면 다음과 같다:
- 로그 경로:
/usr/local/logs/test_api/ - 파일명 패턴:
test-api-dev.log.YYYY-MM-DD.N.gz - 오늘 날짜 기준 15일 이전의 파일 삭제
- crontab으로 자동 실행
1. 삭제 스크립트 (delete_old_logs.sh) 생성
먼저 아래 내용을 스크립트 파일로 저장합니다.
#!/bin/bash
LOG_DIR="/usr/local/logs/test_api"
# 15일 이전의 .gz 파일을 삭제
find "$LOG_DIR" -type f -name "test-api-dev.log.*.gz" -mtime +15 -exec rm -f {} \;
# 로그 남기고 싶다면 (선택사항)
# find "$LOG_DIR" -type f -name "test-api-dev.log.*.gz" -mtime +15 -exec rm -f {} \; -exec echo "Deleted: {}" >> /usr/local/logs/test_api/cleanup.log \;
설명
-type f: 파일만 대상-name "test-api-dev.log.*.gz": 해당 패턴의 로그 파일만 찾음-mtime +15: 수정된지 15일 초과된 파일-exec rm -f {} \;: 찾은 파일 삭제
2. 실행 권한 부여
chmod +x /usr/local/logs/test_api/delete_old_logs.sh
3. crontab 등록
crontab -e
매일 새벽 3시에 실행되게 설정하려면 다음 줄을 추가한다.
0 3 * * * /usr/local/logs/test_api/delete_old_logs.sh >/dev/null 2>&1
4. (선택) 테스트 방법
오늘 기준으로 테스트하려면 -mtime +15 대신 예를 들어 -mtime +0으로 바꿔서 실행해본다.
bash /usr/local/logs/test_api/delete_old_logs.sh
추가적으로 “삭제 내역을 날짜별로 기록하는 버전”도 만들어보자
(예: /usr/local/logs/test_api/cleanup.log 에 어떤 파일이 언제 삭제됐는지 로그 남기기)
로그는 /usr/local/logs/test_api/cleanup.log 파일에 남긴다.
#!/bin/bash
LOG_DIR="/usr/local/logs/test_api"
LOG_FILE="$LOG_DIR/cleanup.log"
RETENTION_DAYS=15
# 현재 날짜 출력
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 로그 정리 시작 (기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"
# 오래된 로그 파일 찾기
DELETED_FILES=$(find "$LOG_DIR" -type f -name "test-api-dev.log.*.gz" -mtime +$RETENTION_DAYS)
if [ -z "$DELETED_FILES" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 삭제할 파일 없음" >> "$LOG_FILE"
else
# 파일 삭제 및 로그 기록
echo "$DELETED_FILES" | while read -r FILE; do
if [ -f "$FILE" ]; then
rm -f "$FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ 삭제됨: $FILE" >> "$LOG_FILE"
fi
done
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ ${RETENTION_DAYS}일 이전 로그 정리 완료" >> "$LOG_FILE"
fi
echo "" >> "$LOG_FILE"
설명
RETENTION_DAYS=15: 삭제 기준일 (15일 이전 파일)- 삭제 내역이
cleanup.log에 아래처럼 남습니다 👇
[2025-11-13 03:00:00] 🔍 로그 정리 시작 (기준: 15일 이전)
[2025-11-13 03:00:00] 🗑️ 삭제됨: /usr/local/logs/test_api/test-api-dev.log.2025-10-20.0.gz
[2025-11-13 03:00:00] 🗑️ 삭제됨: /usr/local/logs/test_api/test-api-dev.log.2025-10-20.1.gz
[2025-11-13 03:00:00] ✅ 15일 이전 로그 정리 완료
권한 및 cron 등록
chmod +x /usr/local/logs/test_api/delete_old_logs.sh
crontab -e
0 3 * * * /usr/local/logs/test_api/delete_old_logs.sh >> /usr/local/logs/test_api/cleanup_cron.log 2>&1
cleanup_cron.log에는 스크립트 실행 중 에러나 출력이 기록됩니다.cleanup.log는 실제 어떤 파일이 삭제됐는지 기록됩니다.
“cleanup.log를 30일 이상 되면 자동 압축 or 삭제” 되도록 함께 관리하는 추가 스크립트도 만들어보자
(즉, 정리 로그도 무한히 쌓이지 않게 하는 버전이)
최종 버전: /usr/local/logs/test_api/delete_old_logs.sh
#!/bin/bash
LOG_DIR="/usr/local/logs/test_api"
LOG_FILE="$LOG_DIR/cleanup.log"
RETENTION_DAYS=15 # 로그 파일 삭제 기준일
CLEANUP_LOG_ROTATE_DAYS=30 # cleanup.log 관리 기준일
# 로그 시작
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 로그 정리 시작 (기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"
# 오래된 로그 파일 삭제
DELETED_FILES=$(find "$LOG_DIR" -type f -name "test-api-dev.log.*.gz" -mtime +$RETENTION_DAYS)
if [ -z "$DELETED_FILES" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 삭제할 파일 없음" >> "$LOG_FILE"
else
echo "$DELETED_FILES" | while read -r FILE; do
if [ -f "$FILE" ]; then
rm -f "$FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ 삭제됨: $FILE" >> "$LOG_FILE"
fi
done
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ ${RETENTION_DAYS}일 이전 로그 정리 완료" >> "$LOG_FILE"
fi
# cleanup.log 자체 관리 (30일 지난 경우)
if [ -f "$LOG_FILE" ]; then
FILE_DATE=$(date -r "$LOG_FILE" +%s)
NOW_DATE=$(date +%s)
AGE_DAYS=$(( (NOW_DATE - FILE_DATE) / 86400 ))
if [ $AGE_DAYS -ge $CLEANUP_LOG_ROTATE_DAYS ]; then
ARCHIVE_FILE="$LOG_DIR/cleanup_$(date '+%Y-%m-%d').log.gz"
gzip -c "$LOG_FILE" > "$ARCHIVE_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 📦 cleanup.log 압축됨 → $ARCHIVE_FILE" >> "$LOG_FILE"
# cleanup.log 초기화
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔄 cleanup.log 파일 리셋" > "$LOG_FILE"
fi
fi
echo "" >> "$LOG_FILE"
동작 요약
| 기능 | 설명 |
|---|---|
| 🗑️ 로그 삭제 | test-api-dev.log.*.gz 파일 중 15일 이상 된 것 삭제 |
| 📦 cleanup.log 압축 | cleanup.log 파일이 마지막 수정된 지 30일 이상이면 gzip 압축 |
| 🔄 cleanup.log 리셋 | 압축 후 새 cleanup.log로 초기화 |
| 📅 로그 기록 | 모든 실행 내역이 cleanup.log에 남음 |
권한 설정
chmod +x /usr/local/logs/test_api/delete_old_logs.sh
crontab 설정 (매일 새벽 3시 실행)
crontab -e
0 3 * * * /usr/local/logs/test_api/delete_old_logs.sh >> /usr/local/logs/test_api/cleanup_cron.log 2>&1
결과 예시
cleanup.log
[2025-11-13 03:00:00] 🔍 로그 정리 시작 (기준: 15일 이전)
[2025-11-13 03:00:00] 🗑️ 삭제됨: /usr/local/logs/test_api/test-api-dev.log.2025-10-20.0.gz
[2025-11-13 03:00:00] ✅ 15일 이전 로그 정리 완료
[2025-11-13 03:00:00] 📦 cleanup.log 압축됨 → /usr/local/logs/test_api/cleanup_2025-11-13.log.gz
[2025-11-13 03:00:00] 🔄 cleanup.log 파일 리셋
원하신다면 이 스크립트를 서버 여러 경로에 적용할 수 있는 범용 버전(예: 여러 로그 폴더 관리용 LOG_DIRS=("path1" "path2") 배열 지원 버전)으로 만들어드릴 수도 있어요.
“여러 로그 경로”를 한 번에 관리할 수 있는 범용 자동 정리 스크립트 버전을 만들어드릴게요.
이 버전은 복수의 로그 디렉터리를 지정하면, 각각에 대해 15일 이상된 로그를 삭제하고, cleanup 로그도 30일 단위로 압축/초기화합니다.
범용 버전: /usr/local/logs/delete_old_logs_all.sh
#!/bin/bash
# ==========================================================
# 🔧 설정 영역
# ==========================================================
# 로그 디렉토리 여러 개 지정 가능
LOG_DIRS=(
"/usr/local/logs/test_api"
"/usr/local/logs/another_service"
"/usr/local/logs/sample_app"
)
RETENTION_DAYS=15 # 각 서비스 로그 삭제 기준일
CLEANUP_LOG_ROTATE_DAYS=30 # cleanup.log 관리 기준일
# ==========================================================
# 🚀 실행 로직
# ==========================================================
for LOG_DIR in "${LOG_DIRS[@]}"; do
LOG_FILE="$LOG_DIR/cleanup.log"
# 디렉토리 존재 여부 확인
if [ ! -d "$LOG_DIR" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 경로 없음: $LOG_DIR"
continue
fi
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 로그 정리 시작 (디렉토리: $LOG_DIR, 기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"
# 오래된 .gz 로그 삭제
DELETED_FILES=$(find "$LOG_DIR" -type f -name "*.log.*.gz" -mtime +$RETENTION_DAYS)
if [ -z "$DELETED_FILES" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 삭제할 파일 없음" >> "$LOG_FILE"
else
echo "$DELETED_FILES" | while read -r FILE; do
if [ -f "$FILE" ]; then
rm -f "$FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ 삭제됨: $FILE" >> "$LOG_FILE"
fi
done
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ ${RETENTION_DAYS}일 이전 로그 정리 완료" >> "$LOG_FILE"
fi
# cleanup.log 관리
if [ -f "$LOG_FILE" ]; then
FILE_DATE=$(date -r "$LOG_FILE" +%s)
NOW_DATE=$(date +%s)
AGE_DAYS=$(( (NOW_DATE - FILE_DATE) / 86400 ))
if [ $AGE_DAYS -ge $CLEANUP_LOG_ROTATE_DAYS ]; then
ARCHIVE_FILE="$LOG_DIR/cleanup_$(date '+%Y-%m-%d').log.gz"
gzip -c "$LOG_FILE" > "$ARCHIVE_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 📦 cleanup.log 압축됨 → $ARCHIVE_FILE" >> "$LOG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔄 cleanup.log 파일 리셋" > "$LOG_FILE"
fi
fi
echo "" >> "$LOG_FILE"
done
설정 방법
파일 저장 및 권한 부여
sudo vi /usr/local/logs/delete_old_logs_all.sh
sudo chmod +x /usr/local/logs/delete_old_logs_all.sh
LOG_DIRS 수정
관리할 로그 경로를 배열에 넣기만 하면 됩니다 👇
LOG_DIRS=(
"/usr/local/logs/test_api"
"/usr/local/logs/other_api"
"/usr/local/logs/myapp"
)
crontab 등록 (매일 새벽 3시)
crontab -e
0 3 * * * /usr/local/logs/delete_old_logs_all.sh >> /usr/local/logs/cleanup_cron.log 2>&1
결과 예시
각 로그 폴더에 다음과 같은 로그 파일이 생성됩니다 👇
/usr/local/logs/test_api/cleanup.log
[2025-11-13 03:00:00] 🔍 로그 정리 시작 (디렉토리: /usr/local/logs/test_api, 기준: 15일 이전)
[2025-11-13 03:00:00] 🗑️ 삭제됨: /usr/local/logs/test_api/test-api-dev.log.2025-10-20.0.gz
[2025-11-13 03:00:00] ✅ 15일 이전 로그 정리 완료
/usr/local/logs/sample_app/cleanup.log
[2025-11-13 03:00:00] 🔍 로그 정리 시작 (디렉토리: /usr/local/logs/sample_app, 기준: 15일 이전)
[2025-11-13 03:00:00] ✅ 삭제할 파일 없음
보너스 옵션 (선택)
원하면 아래처럼 옵션을 줄 수도 있습니다.
| 옵션 | 설명 |
|---|---|
RETENTION_DAYS=10 | 로그 삭제 기준을 10일로 단축 |
CLEANUP_LOG_ROTATE_DAYS=7 | cleanup.log를 1주일마다 압축/리셋 |
-name "*.gz" | 모든 gzip 로그 포함 (서비스명 상관없이) |
원하시면 이 스크립트를 /etc/logrotate.d 방식으로 통합해서, 시스템 표준 logrotate 정책에 맞게 관리하는 버전도 만들 수 있다.
(즉, cron 없이 logrotate 만으로 자동 압축/삭제/로테이션 수행)
파일이 아래처럼 되어 있는 SLOT_YYYYMMDD_NN.log 형식의 일반 로그 파일의 경우에는 좀 더 복잡하다.
SLOT_20251101_01.log
SLOT_20251101_02.log
SLOT_20251102_01.log
SLOT_20251103_01.log
즉, 날짜는 파일명 중간(SLOT_YYYYMMDD_)에 포함되어 있고, 파일 수정일(mtime)이 아니라 파일명 기준으로 날짜 판단해야 하는 상황이죠.
핵심 아이디어
- 파일명에서 날짜 부분(
YYYYMMDD) 추출 - 현재 날짜(
YYYYMMDD)와 비교 15일 이전이면 삭제
예제 스크립트 (날짜 파싱 기반)
#!/bin/bash
LOG_DIR="/usr/local/logs/test_api"
LOG_FILE="$LOG_DIR/cleanup.log"
RETENTION_DAYS=15
# 현재 날짜 기준 (초 단위)
CURRENT_TS=$(date +%s)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 SLOT 로그 정리 시작 (기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"
# SLOT_YYYYMMDD_*.log 파일 반복 처리
for FILE in "$LOG_DIR"/SLOT_*.log; do
# 파일이 없을 경우 스킵
[ -e "$FILE" ] || continue
# 파일명에서 날짜 부분 추출 (예: SLOT_20251101_01.log → 20251101)
BASENAME=$(basename "$FILE")
FILE_DATE=$(echo "$BASENAME" | grep -oE '[0-9]{8}' | head -1)
# 날짜가 없는 파일은 스킵
if [ -z "$FILE_DATE" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 날짜 추출 실패: $BASENAME" >> "$LOG_FILE"
continue
fi
# 날짜를 초단위 timestamp로 변환
FILE_TS=$(date -d "$FILE_DATE" +%s 2>/dev/null)
# 변환 실패 (잘못된 날짜 형식)
if [ -z "$FILE_TS" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 날짜 변환 실패: $BASENAME" >> "$LOG_FILE"
continue
fi
# (현재 - 파일날짜) → 일수 계산
AGE_DAYS=$(( (CURRENT_TS - FILE_TS) / 86400 ))
# 기준 초과시 삭제
if [ $AGE_DAYS -gt $RETENTION_DAYS ]; then
rm -f "$FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ ${AGE_DAYS}일 경과 → 삭제됨: $BASENAME" >> "$LOG_FILE"
fi
done
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 정리 완료" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
작동 예시
현재 날짜가 2025-11-13일 때:
| 파일명 | 날짜 | 일수 경과 | 처리결과 |
|---|---|---|---|
| SLOT_20251101_01.log | 2025-11-01 | 12일 | 유지 |
| SLOT_20251025_01.log | 2025-10-25 | 19일 | ✅ 삭제 |
| SLOT_20251015_01.log | 2025-10-15 | 29일 | ✅ 삭제 |
crontab 등록 (매일 새벽 3시 실행)
0 3 * * * /usr/local/logs/test_api/cleanup_slot_logs.sh >> /usr/local/logs/test_api/cleanup_cron.log 2>&1
확장 가능 버전
이걸 아까 만든 multi-directory 범용 버전에도 통합할 수 있습니다.
즉, 각 경로별로 "패턴:보관일:형식" 이런 식으로 관리하도록요.
예시
LOG_CONFIGS=(
"/usr/local/logs/test_api:SLOT_*.log:15:filename"
"/usr/local/logs/payment:*.gz:30:mtime"
)
원하신다면 이 “혼합형 (mtime + 파일명 날짜 둘 다 지원)” 버전으로 만들어드릴까요?
즉, 어떤 디렉터리는 mtime 기준, 어떤 곳은 파일명 날짜 기준으로 자동 구분 삭제하는 통합 스크립트입니다.
SLOT_20251101_01.log 파일처럼
API_20251101_01.log
DEV__20251101_01.log 여러개 파일 경우에는?
- 로그 파일명이 다양함
SLOT_20251101_01.log API_20251101_01.log DEV__20251101_01.log - 공통 규칙: 파일명 어딘가에 날짜(YYYYMMDD)가 들어있다.
- 이 날짜를 기준으로 오늘 기준 N일(예: 15일) 이전 파일은 삭제해야 함.
즉, 이제 SLOT, API, DEV__ 등 prefix가 달라도 날짜만 잘 뽑으면 삭제 로직은 동일해야 해요.
통합 버전: cleanup_by_filename_date.sh
#!/bin/bash
LOG_DIR="/usr/local/logs/test_api"
LOG_FILE="$LOG_DIR/cleanup.log"
RETENTION_DAYS=15
CURRENT_TS=$(date +%s)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 파일명 날짜 기반 로그 정리 시작 (기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"
# 모든 .log 파일 순회
for FILE in "$LOG_DIR"/*.log; do
[ -e "$FILE" ] || continue
BASENAME=$(basename "$FILE")
# 파일명에서 날짜 추출 (YYYYMMDD)
FILE_DATE=$(echo "$BASENAME" | grep -oE '[0-9]{8}' | head -1)
# 날짜 없는 파일은 스킵
if [ -z "$FILE_DATE" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 날짜 추출 실패 → $BASENAME" >> "$LOG_FILE"
continue
fi
# 날짜 유효성 검사 (존재하지 않는 날짜 방지)
if ! date -d "$FILE_DATE" >/dev/null 2>&1; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 잘못된 날짜 형식 → $BASENAME" >> "$LOG_FILE"
continue
fi
FILE_TS=$(date -d "$FILE_DATE" +%s)
AGE_DAYS=$(( (CURRENT_TS - FILE_TS) / 86400 ))
# 기준 초과시 삭제
if [ $AGE_DAYS -gt $RETENTION_DAYS ]; then
rm -f "$FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ ${AGE_DAYS}일 경과 → 삭제됨: $BASENAME" >> "$LOG_FILE"
fi
done
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 파일명 날짜 기반 정리 완료" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
동작 방식
| 파일명 | 추출된 날짜 | 경과 일수 | 처리 결과 |
|---|---|---|---|
SLOT_20251101_01.log | 20251101 | 12일 | 유지 |
API_20251020_03.log | 20251020 | 24일 | ✅ 삭제 |
DEV__20251010_01.log | 20251010 | 34일 | ✅ 삭제 |
✅ 스크립트 요약
grep -oE '[0-9]{8}': 파일명에서 8자리 숫자(YYYYMMDD) 추출date -d "$FILE_DATE": 날짜 유효성 검사((CURRENT_TS - FILE_TS) / 86400): 경과 일수 계산rm -f: 15일 초과 시 삭제
crontab 자동 실행 (매일 새벽 3시)
0 3 * * * /usr/local/logs/test_api/cleanup_by_filename_date.sh >> /usr/local/logs/test_api/cleanup_cron.log 2>&1
확장할 수 있는 버전 예시
만약 여러 경로를 관리하려면 아래처럼 LOG_DIRS 배열 버전으로 바꿀 수 있습니다 👇
LOG_DIRS=(
"/usr/local/logs/test_api"
"/usr/local/logs/payment"
"/usr/local/logs/dev"
)
for DIR in "${LOG_DIRS[@]}"; do
# 위에서 작성한 파일명 기반 삭제 로직 반복
done

