Shell Script for Automated Backup Rotation: Daily (7d), Weekly (4w), Monthly (12m), Yearly (Indefinite)


1 views

Managing backup retention policies manually becomes impractical at scale. We need an automated solution that:

  • Preserves daily backups for 7 days
  • Keeps weekly backups for 4 weeks
  • Retains monthly backups for 12 months
  • Archives yearly backups indefinitely

Here's a robust bash script that handles the rotation logic:

#!/bin/bash

# Configuration
BACKUP_DIR="/var/backups"
PREFIX="blog"
RETENTION_DAILY=7
RETENTION_WEEKLY=4
RETENTION_MONTHLY=12

# Create new daily backup
DATE=$(date +%Y%m%d)
tar -cjf "$BACKUP_DIR/$PREFIX-$DATE.tar.bz2" /path/to/data

# Rotation logic
find "$BACKUP_DIR" -name "$PREFIX-*.tar.bz2" | sort | while read file; do
    filename=$(basename "$file")
    filedate=${filename#$PREFIX-}
    filedate=${filedate%.tar.bz2}
    
    # Parse date components
    year=${filedate:0:4}
    month=${filedate:4:2}
    day=${filedate:6:2}
    
    # Convert to epoch for comparison
    filedate_epoch=$(date --date="$year-$month-$day" +%s)
    now_epoch=$(date +%s)
    
    age_days=$(( (now_epoch - filedate_epoch) / 86400 ))
    
    # Determine backup type
    if [ "$day" == "01" ] && [ "$age_days" -gt 365 ]; then
        # Yearly backup (keep forever)
        continue
    elif [ "$day" == "01" ] && [ "$age_days" -le 365 ]; then
        # Monthly backup (keep for 12 months)
        if [ "$age_days" -gt $((RETENTION_MONTHLY * 30)) ]; then
            rm "$file"
        fi
    elif [ $(date --date="$year-$month-$day" +%u) -eq 1 ] && [ "$age_days" -gt 7 ]; then
        # Weekly backup (keep for 4 weeks)
        if [ "$age_days" -gt $((RETENTION_WEEKLY * 7)) ]; then
            rm "$file"
        fi
    else
        # Daily backup (keep for 7 days)
        if [ "$age_days" -gt $RETENTION_DAILY ]; then
            rm "$file"
        fi
    fi
done

Add this to your crontab to run daily at 2 AM:

0 2 * * * /path/to/backup_rotation.sh

To test the rotation logic, create test files with appropriate dates:

# Create sample backup files
touch blog-{20230101..20230131}.tar.bz2
touch blog-{20230201..20230228}.tar.bz2

Then run the script and verify the remaining files match your retention policy.

For production environments, consider adding:

  • Logging with timestamps
  • Error handling for full disks
  • Notification system for failures
  • Checksum verification

When implementing enterprise-grade backup retention policies, we need a solution that:

  • Preserves recent backups at high frequency (daily)
  • Maintains mid-term recovery points (weekly/monthly)
  • Archives historical snapshots (yearly)

Here's how we'll structure the backup directory:

/backups/
├── daily/
├── weekly/
├── monthly/
├── yearly/
└── archive/

This Bash script handles the tiered rotation automatically:

#!/bin/bash

# Configuration
BACKUP_NAME="blog"
RETENTION_DAILY=7
RETENTION_WEEKLY=4
RETENTION_MONTHLY=12
BACKUP_DIR="/backups"

# Create new backup
timestamp=$(date +%Y%m%d)
tar -cjf "$BACKUP_DIR/daily/$BACKUP_NAME-$timestamp.tar.bz2" /path/to/data

# Daily to Weekly promotion (every Sunday)
if [ $(date +%u) -eq 7 ]; then
  oldest_daily=$(ls -t $BACKUP_DIR/daily/ | tail -1)
  cp "$BACKUP_DIR/daily/$oldest_daily" "$BACKUP_DIR/weekly/"
  
  # Cleanup old weekly backups
  ls -t $BACKUP_DIR/weekly/ | tail -n +$((RETENTION_WEEKLY+1)) | xargs -I {} rm "$BACKUP_DIR/weekly/{}"
fi

# Weekly to Monthly promotion (first of month)
if [ $(date +%d) -eq 1 ]; then
  oldest_weekly=$(ls -t $BACKUP_DIR/weekly/ | tail -1)
  cp "$BACKUP_DIR/weekly/$oldest_weekly" "$BACKUP_DIR/monthly/"
  
  # Cleanup old monthly backups
  ls -t $BACKUP_DIR/monthly/ | tail -n +$((RETENTION_MONTHLY+1)) | xargs -I {} rm "$BACKUP_DIR/monthly/{}"
fi

# Yearly archive (January 1st)
if [ $(date +%m%d) -eq "0101" ]; then
  oldest_monthly=$(ls -t $BACKUP_DIR/monthly/ | tail -1)
  cp "$BACKUP_DIR/monthly/$oldest_monthly" "$BACKUP_DIR/yearly/"
fi

Add this to crontab (runs daily at 2AM):

0 2 * * * /path/to/backup_script.sh

To check your backup structure:

# Show retention counts
echo "Daily: $(ls /backups/daily | wc -l)"
echo "Weekly: $(ls /backups/weekly | wc -l)"
echo "Monthly: $(ls /backups/monthly | wc -l)"
echo "Yearly: $(ls /backups/yearly | wc -l)"

For production environments, consider adding:

  • MD5 checksum verification
  • Remote sync to cloud storage
  • Email notifications on failure
  • Log rotation for the script itself