Last active
October 27, 2025 18:29
-
-
Save oberhamsi/13db66c7376a12d63fc97707d2546921 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ----------------------------- | |
| # Configuration | |
| # ----------------------------- | |
| set -ex | |
| SOURCES=( | |
| "/home/" | |
| "/volume1/folder/" | |
| ) | |
| REMOTE="secure:" | |
| CURRENT="$REMOTE/current" | |
| OLD="$REMOTE/old" | |
| KEEP_SNAPSHOTS=300 # Keep last 300 snapshots | |
| MAX_DELETES=10 # Warn if more than this many files deleted | |
| # ----------------------------- | |
| # Backup | |
| # ----------------------------- | |
| TODAY=$(date +%Y-%m-%d) | |
| DAILY_BACKUP="$OLD/$TODAY" | |
| TOTAL_DELETES=0 | |
| EXIT_CODE=0 | |
| echo "[INFO] Starting backup for multiple sources into $CURRENT" | |
| for SRC in "${SOURCES[@]}"; do | |
| RELPATH=$(realpath --relative-to=/ "$SRC") | |
| TARGET_DIR="$CURRENT/$RELPATH" | |
| BACKUP_DIR="$DAILY_BACKUP/$RELPATH" | |
| echo "[INFO] Syncing $SRC → $TARGET_DIR (backup-dir: $BACKUP_DIR)" | |
| # Run sync and capture output | |
| SYNC_OUTPUT=$(rclone sync "$SRC" "$TARGET_DIR" --backup-dir "$BACKUP_DIR" --exclude "**/@eaDir/**" --skip-links --delete-excluded 2>&1) | |
| SYNC_EXIT=$? | |
| echo "$SYNC_OUTPUT" | |
| # Count deleted files from backup-dir (files moved there are "deleted" from current) | |
| if rclone lsf "$BACKUP_DIR" >/dev/null 2>&1; then | |
| DELETES=$(rclone size "$BACKUP_DIR" --json 2>/dev/null | grep -o '"count":[0-9]*' | cut -d: -f2) | |
| if [[ -n "$DELETES" && "$DELETES" -gt 0 ]]; then | |
| echo "[INFO] $DELETES files deleted/changed in $RELPATH" | |
| TOTAL_DELETES=$((TOTAL_DELETES + DELETES)) | |
| fi | |
| fi | |
| if [[ $SYNC_EXIT -ne 0 ]]; then | |
| EXIT_CODE=1 | |
| fi | |
| done | |
| # Check for excessive deletes | |
| if [[ $TOTAL_DELETES -gt $MAX_DELETES ]]; then | |
| echo "[WARNING] Excessive deletes detected: $TOTAL_DELETES files (threshold: $MAX_DELETES)" | |
| EXIT_CODE=1 | |
| fi | |
| # ----------------------------- | |
| # Rotation | |
| # ----------------------------- | |
| echo "[INFO] Performing snapshot rotation" | |
| snapshots=$(rclone lsf "$OLD" --dirs-only | sed 's:/$::' | sort) | |
| if [[ -z "$snapshots" ]]; then | |
| echo "[INFO] No snapshots to rotate" | |
| exit $EXIT_CODE | |
| fi | |
| snapshot_count=$(echo "$snapshots" | wc -l) | |
| echo "[INFO] Found $snapshot_count snapshots" | |
| # Keep last KEEP_SNAPSHOTS | |
| keep_snapshots=($(echo "$snapshots" | tail -n "$KEEP_SNAPSHOTS")) | |
| echo "[INFO] Keeping ${#keep_snapshots[@]} snapshots" | |
| # Delete old snapshots | |
| DELETED_COUNT=0 | |
| for snap in ${snapshots}; do | |
| if [[ ! " ${keep_snapshots[@]} " =~ " ${snap} " ]]; then | |
| echo "[INFO] Deleting old snapshot: $snap" | |
| if rclone purge "$OLD/$snap"; then | |
| DELETED_COUNT=$((DELETED_COUNT + 1)) | |
| else | |
| echo "[ERROR] Failed to delete $snap" | |
| EXIT_CODE=1 | |
| fi | |
| fi | |
| done | |
| echo "[INFO] Deleted $DELETED_COUNT old snapshots" | |
| echo "[INFO] Backup and rotation completed" | |
| exit $EXIT_CODE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment