30일 지난 로그만 골라 지우기: find와 xargs 조합 3가지 안전 명령어

서버 디스크가 90%를 넘겼다는 알림을 받고 부랴부랴 접속해 보면, 십중팔구 범인은 쌓이고 쌓인 로그 파일이더라고요. 그런데 여기서 급한 마음에 rm -rf /var/log/* 같은 걸 쳐버리면 정말 돌이킬 수 없는 사고가 납니다. 필요한 건 “30일 지난 로그만, 딱 그것만” 지우는 정교한 칼질이에요.

오늘은 리눅스 관리자들이 가장 많이 쓰는 조합, find + xargs로 30일 경과 로그를 안전하게 정리하는 명령어 3가지를 정리해 볼게요. 그냥 복붙용 한 줄이 아니라, 왜 이렇게 써야 안전한지까지 같이 짚어드립니다.

먼저: 지우기 전에 반드시 “미리보기”부터

삭제 명령을 짤 때 제 원칙은 하나예요. -delete나 rm을 붙이기 전에, 똑같은 조건으로 목록부터 뽑아본다. 조건이 잘못돼 있으면 목록 단계에서 바로 티가 나거든요.

기본형은 이렇습니다.

find /var/log/myapp -type f -name “*.log” -mtime +30 -print

옵션 하나하나가 다 안전장치입니다.

  • /var/log/myapp : 절대 경로로, 그리고 최대한 좁게. 절대 //var 같은 넓은 범위를 잡지 마세요.
  • -type f : 일반 파일만. 이게 없으면 디렉터리나 심볼릭 링크까지 걸려 사고가 납니다.
  • -name “*.log” : 확장자로 한 번 더 필터. 따옴표를 꼭 씌워야 셸이 아니라 find가 패턴을 해석해요.
  • -mtime +30 : 수정 시각이 30일(정확히는 31일치 경계) 넘은 파일. + 기호를 빼먹으면 “정확히 30일 전 하루치”만 걸려서 전혀 다른 결과가 나옵니다.

여기서 나온 목록을 눈으로 훑어보고, 지워도 되는 파일만 있는지 확인한 뒤에 다음 단계로 넘어가세요. 개수만 빠르게 세고 싶다면 뒤에 | wc -l을 붙이면 됩니다. 용량을 확인하고 싶다면 -print 대신 -printf “%s %p\n”이나 -exec du -ch {} +를 활용해도 좋아요.

명령어 1. 가장 안전한 정석: -print0 과 xargs -0

본론입니다. 첫 번째 방법은 null 문자 구분을 쓰는 정석 조합이에요.

find /var/log/myapp -type f -name “*.log” -mtime +30 -print0 | xargs -0 -r rm -f

왜 굳이 -print0-0을 쌍으로 쓸까요? 기본 xargs는 공백과 개행을 파일명 구분자로 인식합니다. 그래서 app error 2024.log처럼 공백이 들어간 파일이 있으면, xargs가 이걸 app, error, 2024.log 세 개의 파일로 쪼개서 rm에 넘겨요. 운 나쁘게 그 이름과 일치하는 다른 파일이 있으면 엉뚱한 게 날아갑니다.

-print0은 파일명을 널 문자(\0)로 구분해서 넘기고, xargs -0은 그걸 그대로 받아요. 파일명에 공백이든 따옴표든 개행이든 들어 있어도 절대 쪼개지지 않습니다. 로그 파일명에 공백이 잘 없다고 방심하기 쉬운데, 배포 스크립트가 만든 이상한 이름이 섞여 있는 경우가 은근히 많아요.

추가로 챙길 옵션도 정리해 둘게요.

  • -r (또는 –no-run-if-empty) : 결과가 하나도 없을 때 rm을 아예 실행하지 않게 합니다. 이게 없으면 인자 없는 rm이 실행되면서 에러 로그가 지저분하게 남아요.
  • -t : 실행할 명령을 화면에 출력해 줍니다. 첫 실행 때 붙여보면 뭘 지우는지 눈으로 확인 가능해요.
  • -p : 실행 전에 y/n을 물어봅니다. 진짜 조심스러운 상황에 유용해요.
  • echo 리허설 : xargs -0 -r echo rm -f처럼 앞에 echo를 붙이면 실제로는 아무것도 안 지우고 명령문만 출력됩니다. 크론에 등록하기 전 필수 단계예요.

명령어 2. 파일 수가 수만 개일 때: -n 과 -P 로 나눠서 처리

로그가 수십만 개 쌓인 디렉터리에서 한 번에 삭제를 시도하면 Argument list too long 에러를 만나거나, I/O가 몰려 서비스가 순간적으로 느려질 수 있어요. 이럴 땐 xargs의 분할 기능을 씁니다.

find /var/log/myapp -type f -name “*.log” -mtime +30 -print0 | xargs -0 -r -n 200 -P 2 rm -f

  • -n 200 : rm 한 번에 파일 200개씩만 넘깁니다. 인자 길이 제한 문제를 원천 차단하고, 중간에 끊겨도 피해 범위가 작아요.
  • -P 2 : 프로세스 2개를 병렬로 돌립니다. 삭제가 빨라지지만 디스크 부하도 같이 올라가니, 운영 중인 서버에서는 2~4 정도로만 잡는 게 안전해요.

부하가 정말 걱정된다면 ionice -c3이나 nice를 앞에 붙여서 우선순위를 낮추는 방법도 있습니다. 예를 들어 xargs -0 -r -n 200 ionice -c3 rm -f 식으로요. 새벽 배치라면 병렬 없이 천천히 도는 편이 오히려 마음 편하더라고요.

명령어 3. 지우기 전에 백업/압축까지: xargs -I 로 한 번 더 감싸기

“지우긴 지워야 하는데 혹시 몰라 한 달치는 압축해서 남기고 싶다”는 요구, 정말 많죠. 이럴 땐 xargs의 -I 옵션으로 파일 하나하나에 명령을 적용합니다.

find /var/log/myapp -type f -name “*.log” -mtime +30 -print0 | xargs -0 -r -I{} mv {} /backup/logs/

이렇게 옮겨두고 나중에 확인 후 지우는 게 가장 마음이 편한 방식이에요. 압축까지 한 번에 하려면 이렇게도 씁니다.

find /var/log/myapp -type f -name “*.log” -mtime +30 -print0 | xargs -0 -r -I{} gzip -9 {}

다만 -I는 파일마다 프로세스를 하나씩 띄우기 때문에 개수가 많으면 확연히 느립니다. 그래서 저는 보통 이렇게 나눠 써요.

  • 30~90일 구간 : gzip으로 압축만 (-mtime +30 -mtime -90 조건으로 구간 지정)
  • 90일 초과 : xargs -0 rm -f로 완전 삭제

참고로 순수하게 삭제만 할 거라면 사실 xargs 없이 find … -deletefind … -exec rm -f {} +가 더 간단하고 안전합니다. 파이프를 안 거치니 파일명 문제도 없고요. xargs 조합의 진짜 가치는 병렬 처리, 개수 분할, 다른 명령과의 조합이 필요할 때 드러납니다. 상황에 맞게 골라 쓰시면 돼요.

크론에 걸기 전 체크리스트

  • 경로를 변수로 빼지 말고 절대 경로로 직접 적기. 변수가 비면 rm -rf $DIR/*가 루트를 향합니다.
  • 크론은 셸 환경이 다르므로 find, xargs, rm 모두 전체 경로(/usr/bin/find 등)로 적어주기.
  • 실행 로그를 남기기. >> /var/log/cleanup.log 2>&1을 붙여두면 사고 추적이 쉬워집니다.
  • 서비스가 열어둔 채로 쓰고 있는 로그 파일은 지워도 디스크가 안 비어요. logrotate와 역할을 나누는 게 좋습니다.
  • 처음 한 번은 반드시 echo 리허설 → 수동 실행 → 크론 등록 순서로.

정리하면, 핵심은 세 가지예요. 범위를 좁히고(-type f, -name, 절대 경로), 구분자를 안전하게 넘기고(-print0 | xargs -0), 지우기 전에 반드시 목록을 확인한다. 이 순서만 지키면 새벽에 식은땀 흘릴 일은 거의 없습니다. 오늘 바로 여러분 서버의 로그 디렉터리에서 -print 버전부터 한번 돌려보세요.

함께 읽으면 좋은 글들