Log Rotation and Cleanup
find is the standard tool for enforcing file retention policies — compressing old logs, deleting ancient ones, and cleaning up empty directories left behind.
The Three-Stage Retention Pattern
Most retention policies have three stages:
Stage 1: Compress → logs older than 7 days → gzip them
Stage 2: Archive → logs older than 30 days → move to cold storage
Stage 3: Delete → logs older than 90 days → remove permanently
Stage 1: Compress Logs Older Than 7 Days
# Find uncompressed logs older than 7 days and gzip them
find /var/log/nginx -type f -name "*.log" ! -name "*.gz" -mtime +7 \
-exec gzip {} +
The + at the end batches all matched files into a single gzip call — far more efficient than one process per file.
Stage 2: Delete Compressed Logs Older Than 30 Days
find /var/log/nginx -type f -name "*.gz" -mtime +30 -delete
Stage 3: Remove Empty Directories Left Behind
After rotating, parent date-named directories may be empty:
find /var/log/nginx -mindepth 1 -type d -empty -delete
-mindepth 1 ensures we never delete the /var/log/nginx root itself.
Full Maintenance Script (Cron-Ready)
#!/bin/bash
# /usr/local/bin/log-retention.sh
# Runs via: 0 2 * * * /usr/local/bin/log-retention.sh
LOG_DIR="/var/opt/myapp/logs"
# Safety check
if [[ ! -d "$LOG_DIR" ]]; then
echo "ERROR: log dir not found: $LOG_DIR" >&2
exit 1
fi
# 1. Dry run first (comment out in production after testing)
echo "=== Would compress (>7d) ==="
find "$LOG_DIR" -type f -name "*.log" ! -name "*.gz" -mtime +7 -print
echo "=== Would delete (>30d) ==="
find "$LOG_DIR" -type f -name "*.gz" -mtime +30 -print
# 2. Actual operations (uncomment for production)
# find "$LOG_DIR" -type f -name "*.log" ! -name "*.gz" -mtime +7 -exec gzip {} +
# find "$LOG_DIR" -type f -name "*.gz" -mtime +30 -delete
# find "$LOG_DIR" -mindepth 1 -type d -empty -delete
Warning: Do Not Delete Open Files
If app.log is open by a running process, deleting it with find -delete will remove the directory entry but the process will keep writing to the open file descriptor. The disk space is not freed until the process is restarted.
# Check which processes have a log file open
lsof /var/log/myapp/app.log
# Safe pattern: only target rotated files (with date in name)
find /var/log/myapp -type f -name "app.log.[0-9]*" -mtime +7 -delete