rokom-cli-backup-ultimativ4

Ultimatives Backup-Script – advanced

Thema: Erweitertes vollautomatisches Backup mit Komfort

Zielgruppe: CLI-Nutzer auf unixoiden Systemen

Motivation: Backup, das einer eierlegenden Wollmilchsau ähnelt

Inhaltsverzeichnis

Attribute des Backup-Script

fun_factor = TRUE
easy_to_use = TRUE
almost_complete = TRUE

Das erweiterte vollautomatische Backup-Script

#!/bin/sh
# Script Name:  usb-backup.sh
# Beschreibung: Inkrementelles Backup auf USB-Medium
# Aufruf:       usb-backup.sh
# Parameter:    keine
# Autor:        Frank Rosenberger - https://ro-kom.de
# Version:      0.3
# Datum:        2023-08-31 - 12:59
# Lizenz:       GPL2 - https://www.gnu.org/licenses/old-licenses/gpl-2.0.html

# 1. BESCHREIBUNG DETAILLIERT ###
# Findet automatisch das USB-Backup-Medium
# Setzt automatisch alle Variablen, auch für differenzierte Log-Dateien 
# Kann mehrfach hintereinander mit verschieden Geräten genutzt werden

# 2. BEREINIGUNG
# Am besten ein eigenes angepasstes Script, hier für Faule, bleachbit.
bleachbit --preset --clean

# 3. PFADFINDER
# Prüftdie angegebenen Pfade.
if [ -d "/run/media/$USER" ]; then
    path="/run/media/$USER/"
elif [ -d "/media/$USER" ]; then
    path="/media/$USER/"
else
    echo "USB-Geräte-Pfad nicht gefunden."
    exit 1
fi

# 4. VARIABLEN
# Ermittelt den ersten Eintrag im angegebenen Pfad, um das Zielgerät zu identifizieren.
find=$(ls -A "$path" | head -n 1)
disk="$path$find"

# Das gefundene Gerät aneignen
group=$(id -gn $USER)
chown -R $group:$USER $path/*  > /dev/null 2>&1

# Hier werden die Pfade für Log-Dateien und andere Verzeichnisse gesetzt.
rl="$HOME/Logs"
file="rsync-$find"
block_device=""

# Das ist der Pfad zur Liste für Ein- und Ausschlüsse von Dateien und Verzeichnissen.
exclude=$HOME/exclude-$find.txt

# Hier sind Quell- und Zielverzeichnisse hinterlegt.
source1=$HOME
target1=$disk
source2=/part2/
target2=$disk/part2/

# Überprüfen, ob das Zielverzeichnis eingehängt ist.
# Wenn nicht, wird eine Fehlermeldung ausgegeben und das Skript beendet.
if ! grep -qs "$disk" /proc/mounts; then
    echo "Zielverzeichnis $disk USB-Laufwerk ist nicht eingehängt."
    exit 1
fi

# 5. LOG
# Funktion zur Log-Rotation
# Rotiert Log-Dateien für das Benutzerverzeichnis "/home/$USER" und "part2".
rotate_logs() {
    local prefix="$1"
    local max_count=7
    
    # Verschiebt bestehende Log-Dateien, um Platz für neue zu machen.
    for i in $(seq $((max_count - 1)) -1 1); do
        if [ -f "$rl/$prefix-$i.log" ]; then
            mv "$rl/$prefix-$i.log" "$rl/$prefix-$((i+1)).log"
        fi
    done
    
    # Verschiebt die aktuelle Log-Datei, falls vorhanden.
    if [ -f "$rl/$prefix.log" ]; then
        mv "$rl/$prefix.log" "$rl/$prefix-1.log"
    fi
}

rotate_logs "$file-$USER"
rotate_logs "$file-part2"

# 6. RSYNC
# Führe rsync-Befehle aus, um Daten zu synchronisieren.
rsync -ahvz --delete --size-only --progress --exclude-from=$exclude --log-file=$rl/$file-$USER.log $source1 $target1
rsync -ahvz --delete --size-only --progress --log-file=$rl/$file-part2.log $source2 $target2

# 7. SHUTDOWN DES USB-GERÄTES
# Ermittle den Blockgerätedateipfad des gefundenen Geräts für das Herunterfahren.
block_device=$(df -P "$disk" | awk 'NR==2 {print $1}')
device_name=$(udevadm info -q path -n "$block_device" | awk -F'/' '{print $NF}')

# Warte 5 Sekunden für eventuelles Journal.
sleep 5s

# Das Gerät aus dem Verzeichnisbaum entfernen.
umount "$disk"

# Warte erneut 5 Sekunde, der Geräte-Gesundheit zuliebe.
sleep 5s

# Schalte das Gerät aus, gib Meldung spiele eine Audio-Datei ab.
udisksctl power-off -b "$block_device" && \
echo ">>>>>  USB-Laufwerk kann jetzt entfernt werden. <<<<<" && \
cvlc --play-and-exit --no-loop "$HOME/Musik/System/EndBackup.mp3" 2>/dev/null

# 8. PC HERUNTERFAHREN
# Hierfür sollten zuerst alle Tasks mit GUI beendet werden und zum Schluss kann der poweroff-Befehl genutzt werden.
# Beispiel für pkill
# Beispiel mit 5 Sekunden Wartezeit: <sudo> shutdown -h -t 5


: '
# 9. EIGENE KOMMENTARE
Hinweis zu 8. PC HERUNTERFAHREN: 
Permanente erweiterte Rechte gehe zu /etc/sudoers
'

Mein Senf dazu

Betriebssysteme

Dieses Shell-Script wird genutzt auf Arch-Linux und Ubuntu.

Dieses Shell-Script sollte in den gängigsten Linux-Ausgaben funktionieren, eventuell auch auf BSD, macOS und „Linux on Windows“. Die Shell-Angabe „sh“ ist in Ihrem OS bestimmt mit einem Zeiger zur eigenen Shell markiert. Zudem können Sie jederzeit den Pfad des Zielgerätes ändern, zum Beispiel auf /mnt/.

Voraussetzungen

  • Betriebssystem mit Shell
  • Pakete: „rsync“, Editor mit Zeilennummern, nicht notwendigerweise „cvlc“ oder „ffplay“
  • Externes USB-Gerät, besser 2 oder 3 Geräte
  • Mögliche Fehlermeldungen zu interpretieren
  • Optional: exclude-list, ansonsten einfach löschen oder auskommentieren
  • Optional: ein Beenden-Jingle, ansonsten einfach löschen oder auskommentieren

Noch einen Hinweis, ich gehe davon aus, dass Ihre Datenträger vernünftig gelabelt sind.
Beispielsweise „x4t“ für externe Festplatte mit 4 Terabyte, denn das wäre wichtig für die Namensgebung der Log-Dateien.

Fähigkeiten in Reihenfolge

Im Wesentlichen wird jedes eingesteckte USB-Gerät als Sicherung genutzt, wenn dieses Bash-Script ausgeführt wird. Jedes Gerät wird dem Benutzer zugeordnet und bekommt individuelle Logdateien.

  1. Bereinigung vor Sicherung -> vollautomatisch
  2. Pfad finden der eingehängten USB-Geräte -> vollautomatisch
  3. Variablen setzen -> vollautomatisch
  4. Fremdes und jedes USB-Gerät aneignen -> vollautomatisch
  5. Die Möglichkeit einer zweiten und weiteren Sicherungen
  6. Logdateien je USB-Gerät -> vollautomatisch
  7. „exclude-list.txt“ für globale Werte oder für differenzierte Sicherungen „exclude-$find.txt“ manuell erstellen
  8. Auswerfen des USB-Gerätes
  9. Strom abschalten des USB-Gerätes für sicheres Entfernen

exclude-list

Das wichtigste, mit dieser Option können auch Sicherungen angelegt werden, auf Medien, die kleiner sind als die gesamte /home-Partition. Mit der Selektierung können nicht priorisierte Daten vernachlässigt werden.

Zur Beachtung, nur relative Pfade zum Quellverzeichnis nutzen.

Zur weiteren Beachtung, zuerst die Einschlüsse und dann erst die Ausschlüsse. Das sollte selbstverständlich sein, da es eine Stapelverarbeitung ist.

Diese Arbeit kann ich niemandem abnehmen. Aber ich gebe ein Beispiel für Ein- und Ausschlüsse für die oben beispielhaft erwähnte „x4t“, also für die „$HOME/exclude-x4t.txt“.

+ .cache/abc/abc.ini
- .cache
- .local/share/Trash
- /Downloads
- /Videos

Quell- und Zielverzeichnisse

Ich habe hier zwei Sicherungen eingetragen. Anhand dieses Beispiel kann natürlich skaliert werden, zum Beispiel bis „part999“.

Denn es könnte sein, dass Sie, so wie ich, für virtuelle Maschinen ein völlig separates Verzeichnis besitzen oder woanders im Wurzel-Verzeichnis noch andere Dinge sichern möchten.

Logdateien

Die Logdateien habe ich wie folgt ausgestattet.

  • „move“ statt „copy“, damit die ursprüngliche Erstellungszeit beibehalten wird
  • Außerdem sind mit „mv“ verständlichere und kürzere Dateinamen möglich
  • Präfixe für differenzierte Logs je Gerät
  • Begrenzung auf 7 Logdateien je Gerät, kann angepasst werden

Die Begrenzung auf 7 Logdateien kommt aus meinen Gedanken, dass ich bei einem Einzelunternehmer oder Privat eine wöchentliche Sicherung als ausreichend erachte. Damit sind es 7 Wochen, die gelogt werden, also 1,5 Monate.

Auch hier ist die Skalierung sehr einfach:

rotate_logs "$file-$USER"
rotate_logs "$file-part2"
rotate_logs "$file-part999"

rsync

In dem Aufruf habe so viel wie möglich für eine sehr schnelle inkrementelle Sicherung eingebaut. Somit sollte eine normale wöchentliche Sicherung weniger als 2 Minuten benötigt.

Ein Trockenlauf funktioniert mit der Option „-n“.

  • a = Alle Archivierungsoptionen
  • h = human-readable, das erklärt sich von selbst
  • v = verbose, also erzähle alles ausführlich
  • z = komprimiere für schnelle Übertragung der Daten
  • delete = in der Quelle entfernte Daten, werden im Ziel gelöscht
  • size-only = ich gehe davon aus das veränderte Daten ihre Größe ändern, diese Einstellung beschleunigt immens
  • progress = für neugierige Menschen
  • exclude = die Filterung, diese Einstellung beschleunigt sehr
  • logfile = na klar, die Logdatei
  • $source = Quellverzeichnis
  • $target = Zielverzeichnis

Das Gerät behutsam aus dem System nehmen

  1. Da vermutlich nur Blockgeräte unmountet werden können, hier die Ermittlung des Gerätes als Blockgerät
  2. Die ersten 5 Sekunden habe ich dem sauberen Journaling gegeben
  3. Dann wird das Gerät aus dem Verzeichnisbaum genommen
  4. Die letzten 5 Sekunden Wartezeit für den Arbeitsspeicher, um die entsprechenden Arrays zu leeren
  5. Nun wird der Strom abgeschaltet für eine konfliktfreie Entfernung des Gerätes
  6. Wirklich erst, wenn Punkt 5 abgeschlossen ist, kommt eine Meldung
  7. Und wirklich erst, wenn die Meldung angezeigt wird, kann der Jingle abgespielt werden, für eine letzte Bestätigung des Geräte-Auswurfs

Optionales Herunterfahren des PC

Im Weiteren kann ein „poweroff“ des PC nur mit erweiterten Rechten oder mit einem Eintrag dieses Bash-Scriptes in der „/etc/sudoers“ realisiert werden.

Was ist noch möglich

  • Selbstverständlich ist es Ihnen überlassen, ob Sie noch eine Formatierung durchführen oder gar erst ein neues oder anderes Dateisystem auf dem USB-Gerät erstellen und das alles innerhalb dieses Bash-Script.
  • Weiterhin ist mit dem „speech-dispatcher“ ein Audio-Ausgabe des Backups realisierbar.
  • Wer sich die Arbeit machen möchte, kann auch über Dialoge die Variablen abfragen, beispielsweise mit den Werkzeugen „echo“, „read“, „find“ und „cat“.
  • Für meinen Vorschlag, mit dem Beenden der meisten Tasks mit GUI vor dem „shutdown“ des PC, hier mal zwei schnelle Ideen für XFCE bis Version 4.18. Vorsicht, alle PID von $USER zu töten, beendet auch das Script vorzeitig.
# Schwellenwert für den Arbeitsspeicherverbrauch in KB
threshold=63488  # 62 MB in KB (1 MB = 1024 KB)

# Erhalten Sie eine Liste der Prozesse, die mehr Arbeitsspeicher als die Schwelle verbrauchen
process_list=$(ps aux --sort=-rss | awk -v threshold="$threshold" '$6 > threshold {print $2}')

# Beenden Sie die ausgewählten Prozesse
for process_id in $process_list; do
    kill -TERM "$process_id"
done

echo "Alle GUI-Programme mit mehr als 62 MB Arbeitsspeicherverbrauch wurden beendet."

Alternative:

# Benutzername, dessen Prozesse beendet werden sollen
TARGET_USER="$USER"

# Durchsuchen Sie alle laufenden Prozesse des Benutzers
for PID in $(pgrep -u "$TARGET_USER"); do
  # Prozessname abrufen
  PROCESS_NAME=$(ps -o comm= -p "$PID")

  # Überprüfen, ob der Prozessname in den Ausnahmen enthalten ist
  if ! [[ "$PROCESS_NAME" =~ ^(.*applet.*|.*aud.*|.*daemon|.*python.*|.*systemd.*|*.py|at-spi.*|bash|dconf.*|gp.*|gvf.*|panel.*|rsync.*|ssh.*|Thunar|x.*)$ ]]; then
    # Wenn der Prozessname nicht in den Ausnahmen enthalten ist, beenden Sie den Prozess
    echo "Beende Prozess: $PROCESS_NAME (PID: $PID)"
    kill "$PID"
  fi
done

echo "Fast alle Prozesse, außer der Desktop-Umgebung XFCE, wurden beendet."

Ihre Mitarbeit

Wenn jemand Verbesserungen anbietet und ich diese erkenne, kann dieses Script für alle optimiert werden.
Voraussetzung, es muss eine Allgemeingültigkeit haben, denn ein Lieblingsprogramm von jemanden, muss nicht zwangsläufig überall zur Verfügung stehen.
Bitte nutzen Sie das Kontaktformular.


Ihr Kom­men­tar [Pos1] Sei­ten­an­fang