#!/usr/bin/env bash # # konsolidierung.sh # # Konsolidiert die Archiv-Ordner eines rsync/rclone-Archivs: # # Struktur im Archiv: JJJJ-MM-TT-HH/ (z. B. 2026-08-03-14) # # 1. Alle Tages-Ordner eines *abgelaufenen* Monats werden zu einem # Monatsordner JJJJ-MM zusammengefasst. Dabei gewinnt immer die # aktuellste Version einer Datei (der spaetere Lauf ueberschreibt # den frueheren). Der aktuelle Monat bleibt unangetastet. # 2. Monatsordner, die aelter als RETAIN_MONTHS Monate sind, werden # zu einem Jahresordner JJJJ zusammengefasst (gleiche Regel: # neuere Version gewinnt). # # Nutzung: # ./konsolidierung.sh [-n] /pfad/zum/archiv # -n = Dry-Run (zeigt nur, was passieren wuerde) # set -euo pipefail DRY_RUN=0 RETAIN_MONTHS=3 # Monatsordner juenger als x Monate bleiben Monatsordner LOG_FILE="" # optional: z. B. LOG_FILE=archiv.log setzen # Log-Ausgabe: mit Zeitstempel auf Terminal und (falls gesetzt) ins Logfile. log() { local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*" echo "$msg" [ -n "$LOG_FILE" ] && echo "$msg" >> "$LOG_FILE" } usage() { echo "Usage: $0 [-n] " >&2; exit 1; } while getopts "n" opt; do case "$opt" in n) DRY_RUN=1 ;; *) usage ;; esac done shift $((OPTIND - 1)) ARCHIVE="${1:-}" [ -d "$ARCHIVE" ] || { echo "Fehler: Archiv-Verzeichnis '$ARCHIVE' nicht gefunden." >&2; usage; } ARCHIVE="$(cd "$ARCHIVE" && pwd)" # ---- Hilfsfunktionen ------------------------------------------------------- # Letzter abgeschlossener Monat als JJJJ-MM. last_closed_month() { date -d "$(date +%Y-%m-01) -1 day" +%Y-%m } # Monatsdifferenz zwischen zwei Werten JJJJ-MM (a - b), negativ wenn a frueher. month_diff() { local a="$1" b="$2" local ay am by bm ay=${a%%-*}; am=${a##*-} by=${b%%-*}; bm=${b##*-} echo $(( (10#$ay * 12 + 10#$am) - (10#$by * 12 + 10#$bm) )) } # Fuehrt alle Quellordner (aufsteigend sortiert, aeltester zuerst) nach DEST # zusammen. Spaetere Laeufe ueberschreiben fruehere => aktuellste Version bleibt. merge_into() { local dest="$1"; shift local src for src in "$@"; do if [ "$DRY_RUN" -eq 1 ]; then log "merge: $src -> $dest (loesche danach: $src)" else log "merge: $src -> $dest" mkdir -p "$dest" cp -a "$src/." "$dest/" rm -rf "$src" fi done } # ---- 1. Tagesordner (JJJJ-MM-TT-HH) zu Monatsordnern (JJJJ-MM) ------------ TODAY_MONTH="$(date +%Y-%m)" CLOSED="$(last_closed_month)" declare -A MONTH_FOLDERS=() for d in "$ARCHIVE"/*; do [ -d "$d" ] || continue base="$(basename "$d")" # exakt JJJJ-MM-TT-HH (4-2-2-2 Ziffern) [[ "$base" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}$ ]] || continue month="${base:0:7}" if [[ "$month" > "$CLOSED" ]]; then continue # aktueller Monat / Zukunft: nicht anfassen fi MONTH_FOLDERS["$month"]+="$d"$'\n' done # pro Monat: aelteste zuerst mergen, neueste gewinnt for month in "${!MONTH_FOLDERS[@]}"; do mapfile -t sources < <(sort <<< "${MONTH_FOLDERS[$month]}" | grep -v '^$') dest="$ARCHIVE/$month" if [ -e "$dest" ]; then # Monatsordner existiert schon (Rest vom letzten Lauf?) -> einfach dazumergen merge_into "$dest" "${sources[@]}" else # ersten (aeltesten) Ordner umbenennen, Rest dazumergen first="${sources[0]}" if [ "$DRY_RUN" -eq 1 ]; then log "mv: $first -> $dest" merge_into "$dest" "${sources[@]:1}" else log "mv: $first -> $dest (Grundordner fuer $month)" mv "$first" "$dest" merge_into "$dest" "${sources[@]:1}" fi fi done # ---- 2. Alte Monatsordner (JJJJ-MM) zu Jahresordnern (JJJJ) --------------- YEAR_FOLDERS=() for d in "$ARCHIVE"/*; do [ -d "$d" ] || continue base="$(basename "$d")" [[ "$base" =~ ^[0-9]{4}-[0-9]{2}$ ]] || continue diff=$(month_diff "${base:0:7}" "$TODAY_MONTH") if [ "$diff" -ge 0 ] || [ $(( -diff )) -lt "$RETAIN_MONTHS" ]; then continue # juenger als RETAIN_MONTHS: als Monatsordner stehen lassen fi YEAR_FOLDERS+=("$d") done if [ ${#YEAR_FOLDERS[@]} -gt 0 ]; then # aelteste zuerst, damit neuere Monatsversionen ueberschreiben mapfile -t YEAR_FOLDERS < <(printf '%s\n' "${YEAR_FOLDERS[@]}" | sort) current_year="" for d in "${YEAR_FOLDERS[@]}"; do yr="$(basename "$d" | cut -c1-4)" dest="$ARCHIVE/$yr" merge_into "$dest" "$d" done fi echo "Fertig." [ "$DRY_RUN" -eq 1 ] && echo "(Dry-Run: nichts wurde veraendert.)"