Files
Hans-Chritian Payer 1d17d6f8ff Neue Datei hochladen
2026-04-28 08:38:29 +00:00

137 lines
3.5 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -Eeuo pipefail
########################################
# Konfiguration
########################################
SRC="${HOME}/"
DEST_BASE="/run/media/hans/usbsicherung/jacboy_sicherung"
HOST="$(hostname -s)"
STAMP="$(date +%F_%H-%M-%S)"
SNAPSHOT_DIR="${DEST_BASE}/${HOST}/${STAMP}"
LAST_LINK="${DEST_BASE}/${HOST}/latest"
LOG_DIR="${DEST_BASE}/${HOST}/logs"
LOG_FILE="${LOG_DIR}/backup-${STAMP}.log"
# Anzahl der aufzubewahrenden Snapshots
KEEP=30
########################################
# Hilfsfunktionen
########################################
log() {
# Schreibt gleichzeitig auf stdout und ins Log (wenn LOG_FILE existiert)
local msg="[$(date +%F\ %T)] $*"
echo "${msg}"
if [[ -n "${LOG_FILE:-}" ]]; then
mkdir -p "$(dirname "${LOG_FILE}")"
echo "${msg}" >> "${LOG_FILE}"
fi
}
fail() {
log "FEHLER: $*"
exit 1
}
########################################
# Vorprüfungen
########################################
# 1. Zielbasis muss existieren und beschreibbar sein
if [[ ! -d "${DEST_BASE}" ]]; then
fail "Zielbasis ${DEST_BASE} existiert nicht oder ist nicht gemountet. Bitte USB-Laufwerk prüfen."
fi
if [[ ! -w "${DEST_BASE}" ]]; then
fail "Zielbasis ${DEST_BASE} ist nicht beschreibbar. Rechte/Mount prüfen."
fi
# 2. Snapshot- und Log-Verzeichnisse anlegen
mkdir -p "${SNAPSHOT_DIR}" "${LOG_DIR}"
log "Starte Backup: ${SRC} -> ${SNAPSHOT_DIR}"
########################################
# rsync-Optionen
########################################
RSYNC_OPTS=(
-aHAXx
--numeric-ids
--delete
--delete-excluded
--info=stats2,progress2
--human-readable
--partial
)
EXCLUDES=(
--exclude=".cache/"
--exclude="Downloads/"
--exclude=".local/share/Trash/"
--exclude=".gvfs/"
--exclude=".dotnet/"
--exclude=".codegpt/"
--exclude=".copilot/"
--exclude=".var/"
--exclude=".vscode/"
#--exclude="temp/"
)
# Wenn es bereits einen gültigen "latest"-Snapshot gibt, diesen als link-dest verwenden
if [[ -L "${LAST_LINK}" ]] && [[ -d "$(readlink -f "${LAST_LINK}")" ]]; then
RSYNC_OPTS+=(--link-dest="$(readlink -f "${LAST_LINK}")")
log "Verwende link-dest: $(readlink -f "${LAST_LINK}")"
else
log "Kein gültiger letzter Snapshot gefunden es wird ein vollständiger Lauf erstellt."
fi
########################################
# rsync-Lauf
########################################
# Optional: Dry-Run zum Testen (auskommentieren, wenn du real sichern willst)
# RSYNC_OPTS+=(--dry-run)
log "Starte rsync..."
if rsync "${RSYNC_OPTS[@]}" \
"${EXCLUDES[@]}" \
"${SRC}" "${SNAPSHOT_DIR}/" | tee -a "${LOG_FILE}"
then
log "rsync erfolgreich abgeschlossen."
else
fail "rsync ist mit einem Fehler beendet worden."
fi
########################################
# latest-Symlink aktualisieren
########################################
ln -sfn "${SNAPSHOT_DIR}" "${LAST_LINK}"
log "latest-Link zeigt jetzt auf ${SNAPSHOT_DIR}"
########################################
# Snapshot-Rotation
########################################
cd "${DEST_BASE}/${HOST}"
# Nur Verzeichnisse mit Datum/Zeit-Präfix (Beginn mit '20') betrachten
SNAPS=(20*/)
if (( ${#SNAPS[@]} > KEEP )); then
log "Rotationslauf: Es existieren ${#SNAPS[@]} Snapshots, KEEP=${KEEP}."
# Sortiert nach Datum (neuestes zuerst), alle älteren als KEEP löschen
ls -1dt 20*/ | tail -n +$((KEEP + 1)) | while read -r old; do
log "Lösche alten Snapshot: ${old}"
rm -rf -- "${old}"
done
else
log "Rotationslauf: Es müssen keine alten Snapshots gelöscht werden (Anzahl: ${#SNAPS[@]}, KEEP=${KEEP})."
fi
log "Backup abgeschlossen."