Komfortables Backup-Skript (rsync) (Update)

In: GNU/Linux

2

Jan

2011

Backup-Skript herunterladen

Und hier noch zur Ansicht (bitte nicht kopieren, da sich dort Fehler eingeschlichen haben könnten):

#!/bin/bash
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#                                                                                       #
# = = = = = = = = = = = = = = = = = = RSYNC BACKUP  = = = = = = = = = = = = = = = = = = #
#                                                                                       #
# Autor:    JaiBee, http://www.321tux.de                                                #
# Datum:    12.06.2011                                                                  #
# Version:  0.98.2                                                                      #
# Lizenz:   Creative Commons "Namensnennung-Nicht-kommerziell-                          #
#           Weitergabe unter gleichen Bedingungen 3.0 Unported "                        #
#           [ http://creativecommons.org/licenses/by-nc-sa/3.0/deed.de ]                #
#                                                                                       #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
# Dieses Skript sichert / synchronisiert Verzeichnisse mit rsync.
# Dabei können beliebig viele Profile konfiguriert oder die Pfade direkt an das Skript übergeben werden.
# Eine kurze Anleitung kann mit der Option -h aufgerufen werden.
 
# WICHTIG: alle Pfadangaben müssen _ohne_ abschließenden Slash (/) angegeben werden!
 
############################### ALLGEMEINE KONFIGURATION ################################
 
# RSYNC_OPT    Optionen für rsync; Verzeichnisse müssen und dürfen nicht angegeben werden
#
# MOUNT        [optional] Einhängepunkt der externen Festplatte
#              vor dem Backup wird überprüft, ob die externe Festplatte eingebunden ist
#
# BAK_DIR      Ordner, in den gelöschte Dateien kopiert werden (--backup-dir=)
#              (die Variable $TARGET, in der das Zielverzeichnis gespeichert ist, ist hierbei nützlich)
 
RSYNC_OPT="-savPbh --delete --numeric-ids --stats"
    MOUNT="/media/Expansion Drive"
function func_bak_dir(){
  BAK_DIR="$TARGET/Geloeschte Dateien/$(date +%F)/"
}
 
############################### KONFIGURATION DER PROFILE ###############################
 
# title[n]     Bezeichnung des Profils; wird u.a. in der Hilfe angezeigt
#
# arg[n]       Argument, mit dem das jeweilige Profil gestartet wird (-p arg[n])
#
# source[n]    Quellverzeichnis(se) (abschließender Slash optional möglich)
#              WICHTIG: Pfadangaben, die Leerzeichen enthalten, müssen von \" umschlossen werden!
#                       Z.B. \"/Verzeichnis mit Leerzeichen/\"
#
# target[n]    Zielverzeichnis
#
# log[n]       [optional] Logdatei, in der die Ausgabe von rsync gespeichert wird
#
# exfrom[n]    temporäre Datei (Standard: $(mktemp -t "tmp.rsync.XXXX")); muss nicht geändert werden
#
# rsync_opt[n] [optional] Optionen für rsync, wenn nicht die Optionen aus $RSYNC_OPT (s.o.) verwendet werden sollen
#
# cat > "${exfrom[1]}" <<EOF       Dateien und Verzeichnisse, die von der Sicherung ausgeschlossen werden sollen
#              pro Zeile 1 Pfad; Pfadangaben mit Leerzeichen müssen nicht gesondert behandelt werden
 
# = = Profil 1  = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
 title[1]="Home-Sicherung"
   arg[1]="h"
source[1]="/home"
target[1]="$MOUNT/Backup"
   log[1]="${target[1]}/${title[1]}-log.txt"
exfrom[1]="$(mktemp -t "tmp.rsync.XXXX")"
rsync_opt[1]=""
cat > "${exfrom[1]}" <<EOF
EOF
 
# = = Profil 2 (optional) = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
 title[2]="Beispiel"
   arg[2]="b"
source[2]="\"/tmp/Verzeichnis 1/mit Leerzeichen\" \"/tmp/Verzeichnis 2\""
target[2]="/tmp/ziel"
   log[2]="${target[2]}/${title[2]}_log.txt"
exfrom[2]="$(mktemp -t "tmp.rsync.XXXX")"
cat > "${exfrom[2]}" <<EOF
.*
unwichtige dateien/
EOF
 
# = = Vorlage für neues Profil (am Besten kopieren)  = = = = = = = = = = = = = = = = = = =
# # [n] ist durch eine Zahl zu ersetzen, z.B. [2] oder [3]
#  title[n]=""
#    arg[n]=""
# source[n]=""
# target[n]=""
#    log[n]="${target[n]}/${title[n]}_log.txt"
# exfrom[n]="$(mktemp -t "tmp.rsync.XXXX")"
# cat > "${exfrom[n]}" <<EOF
#
# EOF
 
################################ ENDE DER KONFIGURATION #################################
 
# Info: wenn das Skript startet, werden die Werte aus den Arrays ausgelesen und in Variablen gespeichert.
# title[n]  -> $TITLE	|	arg[n]    -> $ARG		|	rsync_opt[n] -> $RSYNC_OPT	|	log[n]    -> $LOG
# source[n] -> $SOURCE	|	target[n] -> $TARGET	|	exfrom[n]    -> $EXFROM
 
###################################### FUNKTIONEN #######################################
 
# Wird in der Konsole angezeigt, wenn eine Option nicht angegeben oder definiert wurde
function func_help(){
	echo -e "Aufruf: \033[1m$0 \033[34m-p\033[0m \033[1;36mARGUMENT\033[0m [\033[1;34m-p\033[0m \033[1;36mARGUMENT\033[0m]"
	echo -e "        \033[1m$0 \033[34m-m\033[0m \033[1;36mQUELLE(n)\033[0m \033[1;36mZIEL\033[0m"
	echo
	echo -e "\033[4merforderlich\033[0m"
	for i in $(seq ${#arg[*]});	do echo -e "  \033[1;34m-p\033[0m \033[1;36m${arg[$i]}\033[0m	Profil \"${title[$i]}\""; done
	echo -e "oder\n  \033[1;34m-a\033[0m	alle Backup-Profile"
	echo -e "oder\n  \033[1;34m-m\033[0m	Verzeichnisse manuell angeben"
	echo
	echo -e "\033[4moptional\033[0m"
	echo -e "  \033[1;34m-s\033[0m	PC nach Beendigung automatisch herunterfahren (benötigt u.U. Root-Rechte)"
	echo -e "  \033[1;34m-h\033[0m	Hilfe anzeigen"
	echo
	echo -e "\033[4mBeispiele\033[0m"
	echo -e "  \033[32mProfil \"${title[2]}\"\033[0m starten und den Computer anschließend \033[31mherunterfahren\033[0m:"
	echo -e "	$0 \033[32m-p${arg[2]}\033[0m \033[31m-s\033[0m\n"
	echo -e "  \033[33m\"/tmp/Quelle1/\"\033[0m und \033[35m\"/Leer zeichen2/\"\033[0m mit \033[36m\"/media/extern\"\033[0m synchronisieren; anschließend \033[31mherunterfahren\033[0m:"
	echo -e "	$0 \033[31m-s\033[0;4mm\033[0m \033[33m/tmp/Quelle1\033[0m \033[4m\"\033[0;35m/Leer zeichen2\033[0;4m\"\033[0m \033[36m/media/extern\033[0m"
 
	func_exit
}
 
function func_exit(){
	rm ${exfrom[*]}
	exit 1
}
 
function func_settings(){
	if [[ "$PROFIL" != "customBak" ]]; then
		# Benötigten Werte aus dem Array holen
		for i in $(seq ${#arg[*]}); do								# Anzahl der vorhandenen Profile ermitteln
			if [[ "${arg[$i]}" == "$PROFIL" ]]; then				# wenn das gewünschte Profil gefunden wurde
				TITLE="${title[$i]}";		ARG="${arg[$i]}"
				SOURCE="${source[$i]}";		TARGET="${target[$i]}"
				LOG="${log[$i]}";			EXFROM="${exfrom[$i]}"
				[[ "${rsync_opt[$i]}" != "" ]] && RSYNC_OPT="${rsync_opt[$i]}"
			fi
		done
	fi
	[ "$SOURCE" == "/" ] && TARGET="${TARGET}/ROOTFS"				# Workaround für "/"
}
 
######################################### START #########################################
 
# Wenn eine grafische Oberfläche vorhanden ist, wird u.a. "notify-send" für Benachrichtigungen verwendet, ansonsten immer "echo"
NOTIFY="echo"
[ -n "$DISPLAY" ] && NOTIFY="notify-send"
 
tty -s && clear
echo -e "\033[44m \033[0m\033[1m RSYNC BACKUP\033[0m\n\033[44m \033[0m 2011 by JaiBee, http://www.321tux.de/\n";
 
while getopts ":p:am:sh" opt
do
	case $opt in
		p) for i in "$OPTARG"; do P="$P $i"; done ;;	# bestimmte(s) Profil(e)
		a) P=${arg[*]} ;;								# alle Profile
		m) # eigene Verzeichnisse an das Skript übergeben
			for i in "$@"; do 							# letzte Pfad als Zielverzeichnis
				[ -d "$i" ] && TARGET="$i";
			done
			for i in "$@"; do							# alle übergebenen Verzeichnisse außer $TARGET als Quelle
				[[ -d "$i" && "$i" != "$TARGET" ]] && SOURCE="$SOURCE \"$i\""
			done
			TARGET="$(echo $TARGET | sed -e 's/\/$//')"	# Slash am Ende entfernen
			P="customBak";					TITLE="Custom Backup"
			LOG="$TARGET/$TITLE-log.txt";	MOUNT="" ;;
		s) SHUTDOWN=0 ;;								# Herunterfahren gewählt
		h) func_help ;;									# Hilfe anzeigen
		?) echo -e "\033[1;41m FEHLER \033[0;1m Option ungültig.\033[0m\n" && func_help ;;
	esac
done
 
# Sind die benötigen Programme installiert?
which rsync mktemp wall sed $NOTIFY > /dev/null || { echo "Sie benötigen die Programme rsync, mktemp, wall, sed und $NOTIFY zur Ausführung dieses Skriptes."; func_exit; }
 
# wenn $P leer ist, wurde die Option -p oder -a nicht angegeben
[[ -z "$P" ]] && echo -e "\033[1;41m FEHLER \033[0;1m es wurde kein Profil gewählt\033[0m\n" && func_help
 
# folgende Zeile auskommentieren, falls zum Herunterfahren des Computers Root-Rechte erforderlich sind
#[[ "$SHUTDOWN" == "0" && "$(whoami)" != "root" ]] && echo -e "\033[1;41m FEHLER \033[0;1m Zum automatischen Herunterfahren sind Root-Rechte erforderlich.\033[0m\n" && func_help
 
[ "$SHUTDOWN" == "0" ] && echo -e "  \033[1;31mDer Computer wird nach Durchführung des Backups automatisch heruntergefahren!\033[0m"
 
for PROFIL in $P; do
	func_settings
	func_bak_dir
 
	# /ROOTFS aus $BAK_DIR entfernen
	BAK_DIR="${BAK_DIR//\/ROOTFS/}"
 
	# wurden der Option -b gültige Argument zugewiesen?
	[[ "$PROFIL" != "$ARG" && "$PROFIL" != "customBak" ]] && echo -e "\033[1;41m FEHLER \033[0;1m -p wurde nicht korrekt definiert.\033[0m\n" && func_help
 
	# Konfiguration zu allen gewählten Profilen anzeigen
	echo -e "  \033[4m\nKonfiguration von \033[1m$TITLE\033[0m"
	echo -e "\033[46m \033[0m Quellverzeichnis(se):\033[1m\t$SOURCE\033[0m\n\033[46m \033[0m Zielverzeichnis:\033[1m\t$TARGET\033[0m"
	echo -e "\033[46m \033[0m Log-Datei:\033[1m\t\t$LOG\033[0m"
	if [[ "$PROFIL" != "customBak" ]]; then echo -e "\033[46m \033[0m Exclude:"; sed 's/^/\t\t\t/' $EXFROM ; fi
done
 
for PROFIL in $P; do
	func_settings
 
	# ist die Festplatte eingebunden?
	[[ "$TARGET" == "$MOUNT"* && ! $(mount | grep "$MOUNT") ]] && echo -e "\033[1;41m FEHLER \033[0;1m Die Festplatte ist nicht eingebunden.\033[0m (\"$MOUNT\")" && func_exit
 
	# ggf. Zielverzeichnisse erstellen
	[ ! -d "$TARGET" ]  && { mkdir -vp "$TARGET" || func_exit ;}
	[ ! -d "$BAK_DIR" ] && { mkdir -p "$BAK_DIR" || func_exit ;}
 
	echo -e "\n\033[1m$TITLE wird in 5 Sekunden gestartet.\033[0m"
	echo -e "\033[46m \033[0m Zum Abbrechen [Strg] + [C] drücken\n\033[46m \033[0m Zum Pausieren [Strg] + [Z] drücken (Fortsetzen mit \"fg\")\n"
	sleep 5
	$NOTIFY "Backup startet (Profil: \"$TITLE\")"
 
	# Backup mit rsync starten
	eval rsync $RSYNC_OPT --log-file=\"$LOG\" --exclude-from=\"$EXFROM\" --backup-dir=\"$BAK_DIR\" $SOURCE \"$TARGET\"
 
	echo -e "\a\n\n\033[1m$TITLE wurde abgeschlossen\033[0m\nWeitere Informationen sowie Fehlermeldungen sind in der Datei \"$LOG\" gespeichert.\n"
done
 
rm ${exfrom[*]}
 
# ggf. Herunterfahren
if [ "$SHUTDOWN" == "0" ] ; then
	# Möglichkeit, das automatische Herunterfahren noch abzubrechen
	$NOTIFY "Backup(s) abgeschlossen. ACHTUNG: Der Computer wird in 5 Minuten heruntergefahren. Führen Sie \"kill -9 $(ps -A | grep -m1 "$(basename "$0")" | cut -d " " -f2)\" aus, um das Herunterfahren abzubrechen."
	sleep 1
	echo "This System is going DOWN for System halt in 5 minutes! Run \"kill -9 $(ps -A | grep -m1 "$(basename "$0")" | cut -d " " -f2)\" to  cancel shutdown." | wall
	echo -en "\a\033[1;41m ACHTUNG \033[0m Der Computer wird in 5 Minuten heruntergefahren.\n\n"
	echo -e "Bitte speichern Sie jetzt alle geöffneten Dokumente oder drücken Sie \033[1m[Strg] + [C]\033[0m,\nfalls der Computer nicht heruntergefahren werden soll.\n"
	sleep 5m
	# verschiedene Befehle zum Herunterfahren mit Benutzerrechten [muss evtl. an das eigene System angepasst werden!]
	# Alle Systeme mit HAL || GNOME DBUS || KDE DBUS || GNOME || KDE
	# Root-Rechte i.d.R. erforderlich für "halt" und "shutdown"!
	dbus-send --print-reply --system --dest=org.freedesktop.Hal /org/freedesktop/Hal/devices/computer org.freedesktop.Hal.Device.SystemPowerManagement.Shutdown || \
	dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.RequestShutdown || \
	dbus-send --print-reply --dest=org.kde.ksmserver /KSMServer org.kde.KSMServerInterface.logout 0 2 2 || \
	gnome-power-cmd shutdown || dcop ksmserver ksmserver logout 0 2 2 || \
	halt || shutdown -h now
else
	$NOTIFY "Backup(s) abgeschlossen."
fi

Seiten: 1 2

Werbung:

58 Kommentare zu Komfortables Backup-Skript (rsync) (Update)

» Kommentar schreiben

Avatar

Alex

2. Januar 2011 um 20:34

Sehr schönes Skript, habe bisher eigene recht simple rsync-Skripte benutzt. Ich werd das hier mal testen und gegebenfalls darauf umsteigen. Vielen Dank!

Diesen Beitrag zitieren

Avatar

Sivlan

2. Januar 2011 um 21:56

Schönes Script. War bestimmt ein Stück Arbeit. Ich verwende für Backups Bacula :D . Gruss Silvan.

Diesen Beitrag zitieren

Avatar

Janek

3. Januar 2011 um 13:31

Zitat Sivlan :

War bestimmt ein Stück Arbeit.

Das Script ist so nach und nach entstanden. Angefangen habe ich damit vor Jahren, als ich noch kaum Ahnung von Bash-Skripten hatte. Mit der Zeit habe ich immer mehr dazugelernt und dass Skript immer mal wieder verbessert und ausgebaut. Es war daher ein gutes „Projekt“ zum Ausprobieren und Lernen ;-) .

Gruß

Diesen Beitrag zitieren

Avatar

TruckTrain

3. Januar 2011 um 16:16

Sehr gutes Skript, habe es gerade mal runtergeladen und ausprobiert, funktioniert einwandfrei ;)
Das mit dem Profilstart habe ich anfangs nicht so ganz geschnallt, ist aber jetzt kein Problem mehr! Werde das Skript weiterempfehlen,
Danke Dir!!

Diesen Beitrag zitieren

Avatar

Sebastian

3. Januar 2011 um 17:43

Ich verwende backup2l zum Sichern von /etc und /home. Bei diesem hirarchischen multi-level-Backup steigt der benötigte Speicherplatz nämlich nur logarithmisch, trotz differentieller Taktik.

04.01.2010 – Bearbeitet von Janek: Link korrigiert

Diesen Beitrag zitieren

HFs Jotter » Blog Archive » Aus der virtuellen Nachbarschaft [21]

4. Januar 2011 um 11:32

[...] grafische Backup-Programme gibt es mittlerweile auch unter Linux en masse. 321tux.de beschreibt ein Backup-Skript, welches das freie Tool rsync für die (inkrementelle) Sicherung auf eine [...]

Avatar

Bernd

4. Januar 2011 um 14:43

Ich versuchte es neulich mit MyBackupPro. Ging alles wunderbar, bis ich das Backup wieder einspielen wollte. Irgendeine Datei war kaputt, welche? Keine Ahnung. Zum glück habe ich vorher schon mal eins gemacht, so konnte ich dieses verwenden. Ansonsten wäre es das gewesen…

Ein Programm bräuchte es mal, welches Backups auf kaputte Dateien untersucht….

Diesen Beitrag zitieren

Avatar

FriedChicken

5. Januar 2011 um 01:35

Wenn du rsync magst, soltestdu dir mal rdiff-backup anschauen!

Grafische Oberflächen gibt es wenige (z.B. Keep aus KDE3), aber es ist wie rsync auch gut in einem Skript verwendbar.

Diesen Beitrag zitieren

Avatar

Uwe

12. Januar 2011 um 15:01

Wers lieber grafisch mag sollte sich mal grsync ansehen. Da kann man ebenfalls mehrere Jobs komfortabel verwalten.

Diesen Beitrag zitieren

Avatar

maik

21. Januar 2011 um 09:14

Ich nutze auch rsync für os x, ist super und klappt alles gut…
Da ich mich teilweise echt bei der bedienung etwas anstelle,
und irgendwie auch nicht mit Timemachine warm werde ;)

Diesen Beitrag zitieren

Avatar

cirrus7

27. Januar 2011 um 18:20

Sehr schönes Skript. Besonders die farblich aufgeräumte Darstellung gefällt mir sehr gut. Persönlich benutze ich bisher rdiff-backup. Für die Synchronisation von Verzeichnissen zweier Rechner setze ich unison ein. Das läuft ebenfalls über SSH.

Diesen Beitrag zitieren

Avatar

Max

7. Februar 2011 um 20:12

Ich habe bei der Installation von Ubuntu mein Homeverzeichnis verschlüsselt und möchte dieses nun mittels des hier vorgestellten Skriptes auf einer externen Festplatte sichern.
Wie erreiche ich es, dass die gesichterten Daten auf meiner Backup-Platte genauso verschlüsselt sind, wie der Inhalt des Quellverzeichnisses?

Diesen Beitrag zitieren

Avatar

Janek

8. Februar 2011 um 15:08

Hallo Max,

die Daten verschlüsselt zu sichern, dürfte kein Problem sein. Schau mal ins Wiki von ubuntuusers.de (insbesondere die Abschnitte “Systemdateien sichern” und “Daten in codierter Form”; dazu noch Übersicht zu ecryptfs).

Ich bin mir nicht 100%ig sicher, welche Verzeichnisse du sichern musst, aber ich vermute, dass es folgende sind:

/home/.ecryptfs/[benutzer]/.Private
/home/.ecryptfs/[benutzer]/.ecryptfs

Bei einem verschlüsselten Backup solltest du allerdings beachten, dass die Dateien nur noch Datenmüll sind, sobald die Entschlüsselung fehlschlägt (etwa weil das Passwort nicht stimmt oder weil die Schlüsseldateien fehlen)! Teste daher zuvor, ob die Entschlüsselung funktioniert.

Viel Erfolg!

Gruß Janek

Diesen Beitrag zitieren

Avatar

Patrick

16. Februar 2011 um 00:24

Hallo,

ich finde das Script sehr interessant, aber es will bei mir leider nicht so recht. Bin mit Linux allerdings noch unerfahren. Jedenfalls meldet das Script nach Abschluss:

libnotify-Message: Unable to get session bus: ->
dbus-launch failed to autolaunch D-Bus session: ->
Autolaunch error: X11 initialization failed.

rsync: -savPbh: unknown option
rsync error: syntax or usage error (code 1) at main.c(1318) [client=2.6.9]

Eine Log-Datei wird nicht erstellt aber der Vorgang wird als abgeschlossen angezeigt – Keinerlei Inhalt am Ziel ausser erstellte Ordner.

gruss Patrick

Diesen Beitrag zitieren

Avatar

Janek

16. Februar 2011 um 12:27

Hallo Patrick,

Zitat Patrick :

rsync: -savPbh: unknown option
rsync error: syntax or usage error (code 1) at main.c(1318) [client=2.6.9]

Die Fehlermeldung bedeutet, dass rsync mit einer unbekannten Version aufgerufen wurde. Da du eine veraltete Version von rsync verwendest (siehe rsync --version) wird die Option -s nicht unterstützt. Da das Skript aber auch ohne funktionieren sollte, kannst du die Zeile

RSYNC_OPT="-savPbh --delete --numeric-ids --stats"

durch folgende ersetzen:

RSYNC_OPT="-avPbh --delete --numeric-ids --stats"

Dann sollte es funktionieren (hoffentlich ;-) ).

libnotify-Message: Unable to get session bus: ->
dbus-launch failed to autolaunch D-Bus session: ->
Autolaunch error: X11 initialization failed.

Dieser Fehler ist für das Backup selbst nicht relevant, da es sich auf die Benachrichtigungen mit libnotify-bin bezieht. Rufst du das Skript über ein Netzwerk oder in einer Umgebung ohne grafische Oberfläche auf?

Gruß Janek

Diesen Beitrag zitieren

Avatar

Christian

16. Februar 2011 um 13:22

Ganz großes Lob an dich! Du hast dir wirklich viel Mühe gemacht und das Skript funktioniert tadellos bei mir. Ich würde es gerne auch selbst bei mir produktiv einsetzen, allerdings fehlt mir dabei noch eine wichtige Komponente.

Ich würde gerne regelmäßig Backups (beispielsweise jede Woche) machen. Dein Skript überschreibt das ältere Backup immer und listet die Veränderungen auf. Schön wäre noch die Option, dass man die vorherigen Backups noch eine zeitlang behalten kann, dass also jede Woche ein Backup erstellt wird und alle, die älter als 4 Wochen sind, gelöscht werden. Das sehr einfach gehaltene Skript im Wiki von ubuntuusers.de hat diese Funktion integriert. Vielleicht kannst du diese auch noch inegrieren. Leider übersteigt das meine Fähigkeiten.

Gruß Christian

Diesen Beitrag zitieren

Avatar

Janek

16. Februar 2011 um 14:22

Zitat Christian :

Schön wäre noch die Option, dass man die vorherigen Backups noch eine zeitlang behalten kann, dass also jede Woche ein Backup erstellt wird und alle, die älter als 4 Wochen sind, gelöscht werden.

Hallo Patrick,

ohne jetzt zu viel versprechen zu wollen, gehe ich davon aus, dass ich das (früher oder später) umsetzen werde. Mir fehlt momentan dafür leider die Zeit.

Ich würde das dann vermutlich mit rsync --link-dest (wie bei dem Skript im Wiki von ubuntuusers) oder mit rdiff-backup umsetzen.

Momentan werden gelöschte oder veränderte Dateien im Verzeichnis $BAK_DIR gesichert (1 Verzeichnis pro Tag). Das schützt zwar vor versehentlichem Löschen, aber so komfortabel wie mehrere Snapshots ist das natürlich nicht.

Viele Grüße
Janek

Diesen Beitrag zitieren

Avatar

Patrick

1. März 2011 um 23:32

Hallo Janek,

Danke für deine Unterstützung – Die Anpassung half tatsächlich, nun hab ich nur noch einen Fehler auszuräumen:

process 6409: D-Bus library appears to be incorrectly set up; failed to read machine uuid: Failed to open "/var/lib/dbus/machine-id": No such file or directory
See man ....
libnotify-Message: Unable to get session bus: Failed to execute dbus-launch to autolaunch D-Bus session.

Soweit ersichtlich scheint das Backup an sich korrekt ausgeführt zu sein. Falls du hinsichtlich der Ausgabe noch einen Tip hast?

gruss Patrick

Bearbeitet von Janek (02.03.2011): Code-Tag eingefügt

Diesen Beitrag zitieren

Avatar

Janek

2. März 2011 um 08:25

Zitat Patrick :

Soweit ersichtlich scheint das Backup an sich korrekt ausgeführt zu sein. Falls du hinsichtlich der Ausgabe noch einen Tip hast?

Hallo Patrick,

der nun noch vorhandene Fehler hat nichts mehr direkt mit dem Skript zu tun, sondern vermutlich mit D-Bus. Das scheint nicht richtig zu laufen.

Ich habe eben die Fehlermeldung bei Google eingegeben (immer eine gute Möglichkeit, um solchen Probleme auf die Spur zu kommen) und bin auf folgenden Befehl gestoßen:

dbus-uuidgen | sudo tee /var/lib/dbus/machine-id

Der Befehl generiert eine ID und speichert sie in der Datei machine-id, welche bei dir momentan noch nicht existiert.

Vielleicht löst das dein Problem.

Viel Erfolg!
Gruß Janek

Diesen Beitrag zitieren

Avatar

DSIW

4. März 2011 um 16:34

Hallo,
ich nutze das Skript auch schon in der alten Version seit einem Jahr und bin voll zufrieden. Nun benutze ich das neue Skript und habe den Aufruf noch in /etc/cron.daily/ verschoben, damit es täglich automatisch ausgeführt wird.
Vielen Dank!
Gruß

Diesen Beitrag zitieren

Avatar

dug

19. Mai 2011 um 20:17

Hallo,

in der Shell läuft das Skript klasse aber als cron-job bekomme ich es nicht ans laufen.

Bekomme dann ständig folgendes :

/var/bin/backup-321tux.sh: Zeile 64: mktemp: Kommando nicht gefunden.
/var/bin/backup-321tux.sh: Zeile 66: : Datei oder Verzeichnis nicht gefunden
/var/bin/backup-321tux.sh: Zeile 75: mktemp: Kommando nicht gefunden.
/var/bin/backup-321tux.sh: Zeile 76: : Datei oder Verzeichnis nicht gefunden
/var/bin/backup-321tux.sh: Zeile 141: clear: Kommando nicht gefunden.
  RSYNC BACKUP
  2011 by JaiBee, http://www.321tux.de/

/var/bin/backup-321tux.sh: Zeile 166: which: Kommando nicht gefunden.
Sie ben�tigen die Programme rsync, mktemp, wall, sed und libnotify-bin zur Ausf�hrung dieses Skriptes.
/var/bin/backup-321tux.sh: Zeile 123: rm: Kommando nicht gefunden.
-------------------------------------------------------------------------
Ausführung des Skripts beendet. Drücken Sie die Eingabetaste oder Strg+C zum Beenden.
-------------------------------------------------------------------------

Gruß
dug

Bearbeitet von Janek: Codeblock

Diesen Beitrag zitieren

Avatar

Janek

19. Mai 2011 um 20:26

Zitat dug :

Hallo,

in der Shell läuft das Skript klasse aber als cron-job bekomme ich es nicht ans laufen.

Hallo dug,
schau mal: Befehl klappt in Skript und Shell, aber nicht im Cronjob. Vielleicht reicht dir das als Lösungsansatz schon aus.

Gruß Janek

Diesen Beitrag zitieren

Avatar

Stefan

11. Juni 2011 um 08:44

Klasse Skript. wenn ich es per cron laufen lasse bekomem ich folgenden Fehler gemailt: TERM environment variable not set.

Ich habe ein wenig gegoogelt und das als abhilfe gefunden:

clear

durch

if tty -s ; then
  clear
fi

ersetzen… bitte in der nächsten Version einbauen.

Bearbeitet von Janek: Codeblöcke eingefügt.

Diesen Beitrag zitieren

Avatar

Stefan

11. Juni 2011 um 09:08

Kannst Du noch einen Switch einbauen für Systeme ohne grafische Benutzeroberfläche? Ich verwende das Skript unter Debian auf ner SheevaPlug. Die “notify” braucht es da nicht. Ich schicke Dir auch gerne einen Vorschlag…

Diesen Beitrag zitieren

Avatar

Stefan

11. Juni 2011 um 15:27

Mir ist noch aufgefallen, dass wenn man als Quelle “/” angibt, der Ordner “Geloescht Dateien” und das Log im Ziel Ordner landen und beim nächsten Backup gelöscht werden.

Wegen der clear und notify sache, hab ich mal ein wenig gespielt:

NOTIFY=echo # eoch oder notify-send
 
<>
 
if tty -s ; then
   clear
fi
 
<>
	$NOTIFY "Backup(s) abgeschlossen. ACHTUNG: Der Computer wird in 5 Minuten heruntergefahren. Führen Sie "kill -9 $(ps -A | grep -m1 "$(basename "$0")" | cut -d " " -f2)" aus, um das Herunterfahren abzubrechen."
 
<>
 
	$NOTIFY "Backup(s) abgeschlossen."

Bearbeitet von Janek: Codeblock
Bearbeitet von Janek: Code stark gekürzt, da Sonderzeichen ohnehin nicht mehr richtig dargestellt wurden.

Diesen Beitrag zitieren

Avatar

Janek

11. Juni 2011 um 15:50

Hallo Stefan,
danke für deine Verbesserungsvorschläge.
Ich habe dir eine E-Mail gesendet.

Gruß

Diesen Beitrag zitieren

Avatar

Stefan

12. Juni 2011 um 14:59

Hallo Janek,

ich habe inzwischen das modifizierte Skript (aus meiner letzten Mail) auf zwei Linux-Installationen (SheevaPlug – Debian/Squeeze und VDR – Gentoo) am laufen und keine Probleme festgestellt.

Diesen Beitrag zitieren

Avatar

Janek

12. Juni 2011 um 19:36

Hallo Stefan,

es hat bei mir nun etwas länger gedauert, aber ich habe das verbesserte Skript nun veröffentlicht.

Ob echo oder notify-send verwendet wird, muss man nicht selbst konfigurieren, da das Skript nun abhängig vom Inhalt der Umgebungsvariablen $DISPLAY das passende Tool wählt.
Das Root-Workaround habe ich an eine passendere Stelle verschoben.

Ich habe es zwar oben im Text bereits erwähnt, aber nochmals vielen Dank!

Viele Grüße
Janek

Diesen Beitrag zitieren

Avatar

Stefan

13. Juni 2011 um 11:00

Zitat Janek :


Das Root-Workaround habe ich an eine passendere Stelle verschoben.

Hallo Janek,

ich fürchte das Verschieben in die func_settings bewirkt, dass das anschließende func_bak_dir den Ordner Geloeschte Dateien wieder in das Sicherungsverzeichnis legt, was wiederum zum löschen beim nächsten Durchgang führt. Also entweder die Abfrage nach den Funktionen machen oder in der func-bak_dir ebenfalls testen, ob $SOURCE=”/”

Hier die Ausgabe (echo vor dem rsync)

  RSYNC BACKUP
  2011 by JaiBee, http://www.321tux.de/

Konfiguration von SheevaPlug_Root
  Quellverzeichnis(se): /
  Zielverzeichnis:      /mnt/POPPSTAR/_Backup/SheevaPlug/Root/ROOTFS
  Log-Datei:            /mnt/POPPSTAR/_Backup/SheevaPlug/Root/SheevaPlug_Root-log.txt
  Exclude:
                        dev/
                        lost+found/
                        mnt/
                        proc/
                        sys/
                        tmp/
                        var/tmp/

SheevaPlug_Root wird in 5 Sekunden gestartet.
  Zum Abbrechen [Strg] + [C] drücken
  Zum Pausieren [Strg] + [Z] drücken (Fortsetzen mit "fg")

Backup startet (Profil: "SheevaPlug_Root")
eval rsync -savPbh --delete --numeric-ids --stats --log-file="/mnt/POPPSTAR/_Backup/SheevaPlug/Root/SheevaPlug_Root-log.txt" --exclude-from="/tmp/tmp.rsync.QTdE" --backup-dir="/mnt/POPPSTAR/_Backup/SheevaPlug/Root/ROOTFS/Geloeschte Dateien/2011-06-13/" / "/mnt/POPPSTAR/_Backup/SheevaPlug/Root/ROOTFS"

SheevaPlug_Root wurde abgeschlossen
Weitere Informationen sowie Fehlermeldungen sind in der Datei "/mnt/POPPSTAR/_Backup/SheevaPlug/Root/SheevaPlug_Root-log.txt" gespeichert.

Backup(s) abgeschlossen.

Diesen Beitrag zitieren

Avatar

Janek

13. Juni 2011 um 11:38

Zitat Stefan :

ich fürchte das Verschieben in die func_settings bewirkt, dass das anschließende func_bak_dir den Ordner Geloeschte Dateien wieder in das Sicherungsverzeichnis legt, was wiederum zum löschen beim nächsten Durchgang führt.

Oh shit, da war ich wohl etwas voreilig *peinlich*.
Ich lasse nun “/ROOTFS” in $BAK_DIR ersetzen:

BAK_DIR="$(echo "$BAK_DIR" | sed 's//ROOTFS//')"

Danke für deine Rückmeldung!

Ich hoffe, dass ich diesmal nichts übersehen habe.

Gruß Janek

Diesen Beitrag zitieren

Avatar

Daniel

28. Juni 2011 um 13:25

Danke für Dein Script,

das Script mit neustem Update funktioniert super.
ich habe es noch ein wenig angepasst und möchte mein “Addon” der Allgemeinheit zur Verfügung stellen.

Ich habe noch eine Mailfunktion eingebaut (mailserver, wie postfix natürlich vorausgesetzt), so dass nach Fertigstellung des Backups eine eMail versendet wird und die Log-Datei (hier als bzip2) in den Anhang setzt:

Allgemeine Konfiguration:

MAIL="/usr/local/bin/uudeview"   #statt mail, damit Log als Anhang wird
MAILREC="wer@auch.immer" #Mailempfänger
MAILSUBJECTPRAEFIX="Backup Privat" #Beginn des Subjects

.. und das anschließende packen des logs und das versenden

...
else
	$NOTIFY "Backup(s) abgeschlossen."
	#UUDeview is a program that helps you transmit and receive binary files over the Internet
	#it will be used unstead mail, so log will be send as attachment
        #first zip the (maybe very large) log
	bzip2 -f $LOG 
       #then send it via mail
	uuenview -b -s "[$MAILSUBJECTPRAEFIX] Backup(s) erfolgreich abgeschlossen." -m $MAILREC -a  $LOG.$MAILLOGSUFFIX > /dev/null
	#or use otherwise standard mail 
	#$MAIL -s "[$SUBJECTPRAEFIX] Backup Backup(s) abgeschlossen." $MAILREC -a $LOG.$MAILLOGSUFFIX
fi

Da ich kein großer Shellfreak bin, kann es sein, dass es da sicher noch die eine oder andere Norm gibt, die ich vielleicht nicht eingehalten habe, aber es funktioniert…

Wer es braucht, dem sei es gegeben, wer nicht …. der nicht.

Gruß
Daniel

Bearbeitet von Janek am 28. Juni 2011: Syntaxhervorhebung

Diesen Beitrag zitieren

Avatar

Daniel

28. Juni 2011 um 13:29

Ich habe noch die MAILLOGSUFFIX vergessen, diese kommt noch in die allgemeine Konfiguration:

MAILLOGSUFFIX="bz2"

Gruß
Daniel

Bearbeitet von Janek am 28. Juni 2011: Syntaxhervorhebung

Diesen Beitrag zitieren

Avatar

Janek

28. Juni 2011 um 22:52

Hallo Daniel,

herrlich: geben und nehmen – oder umgekehrt, naja, zumindest vielen Dank für deine Erweiterung, welche sicherlich etlichen Leuten behilflich sein wird.

Das Versenden von Mails in Skripten gehört zu den Themen, die ich mir schon immer einmal vornehmen wollte. Da kommt dein Code gerade recht :) .

Gruß Janek

Diesen Beitrag zitieren

Avatar

Daniel

29. Juni 2011 um 13:40

Gerne doch :-) ,

jetzt hab ich nur ein Problem, dass die aktuelle log-Datei am Ende einfach “weg” also gelöscht ist. Sie landet immer automatisch im aktuellen “Geloeschte Dateien” Ordner.
Ich kann mir nicht erklären wo und warum das passiert, hast Du dieses Phänomän auch?

Gruß
Daniel

Diesen Beitrag zitieren

Avatar

Janek

29. Juni 2011 um 14:05

Hallo Daniel,

es ist ganz simpel: der Befehl bzip2 -f $LOG löscht die ursprüngliche Datei, welche dann offenbar beim nächsten Durchlauf im Verzeichnis “Geloeschte Dateien” landet.

Abhilfe schafft die Option -k bzw. --keep:

bzip2 -fk "$LOG"

Damit sollte es eigentlich passen, sofern ich nichts übersehen habe.

Gruß Janek

Diesen Beitrag zitieren

Avatar

Daniel

29. Juni 2011 um 14:15

Zitat Janek :

Hallo Daniel,

es ist ganz simpel: der Befehl bzip2 -f $LOG löscht die ursprüngliche Datei, welche dann offenbar beim nächsten Durchlauf im Verzeichnis “Geloeschte Dateien” landet.

Abhilfe schafft die Option -k bzw. --keep:

bzip2 -fk "$LOG"

Damit sollte es eigentlich passen, sofern ich nichts übersehen habe.

Gruß Janek

Hi Janek,

ja, das ist mir bewusst und sogar gewollt ;-) ,
aber die Datei ist vorher weg:


Privat wurde abgeschlossen
Weitere Informationen sowie Fehlermeldungen sind in der Datei "/media/backup/backup_intern/Privat-log.txt" gespeichert.

bzip2: Can't open input file /media/backup/backup_intern/Privat-log.txt: No such file or directory.
ERROR: Could not stat file /media/backup/backup_intern/Privat-log.txt.bz2: No such file or directory
error while attaching /media/backup/backup_intern/Privat-log.txt.bz2: File I/O Error No such file or directory

Die Privat-log.txt liegt jetzt bei mir direkt nach Fertigstellung im Unterverzeichniss “Geloeschte Dateien”.
Bei dem ersten Backup war sie noch da und es hat alles wie gewünscht funktioniert, aber beim zweiten Durlauf lag sie dann direkt im “Geloeschte Dateien” Ordner …

Diesen Beitrag zitieren

Avatar

Janek

29. Juni 2011 um 14:32

Zitat Daniel :

Die Privat-log.txt liegt jetzt bei mir direkt nach Fertigstellung im Unterverzeichniss “Geloeschte Dateien”.
Bei dem ersten Backup war sie noch da und es hat alles wie gewünscht funktioniert, aber beim zweiten Durlauf lag sie dann direkt im “Geloeschte Dateien” Ordner …

Hatte schon befürchtet, dass es nicht ganz so easy ist… ;)

Der Pfad zur Logdatei, der ja in der Variablen $LOG gespeichert ist, ist korrekt. Daher fällt mir spontan auch keine mögliche Fehlerursache ein.

Hast du irgendetwas an dem Skript verändert, abgesehen von dem Mailversand am Ende? Denn bei mir tritt das beschriebene Problem nicht auf.

Überprüfe bitte, ob du diesen Teil bei dir im Skript auch so vorfindest:

# Backup mit rsync starten
	eval rsync $RSYNC_OPT --log-file="$LOG"

Ich schick dir gleich ne Mail; dann können wir das auch so klären.

Gruß Janek

Diesen Beitrag zitieren

Avatar

Paul

30. Juni 2011 um 10:35

Das Script sieht auf den ersten Blick echt super aus und ist glaube ich genau das was ich mir vorstelle. Zwei Nachfragen:

1. Habe ich richtig verstanden: Bei der ersten Ausführung werden alle Daten kopiert, ab dann nur noch die geänderten Dateien. Gelöschte und alte Versionen von Dateien kommen in ein Verzeichnis mit dem jeweiligen Backupdatum. Es besteht sozusagen eine Versionierung. Korrekt?

2. Ich möchte auf eine externe Festplatte sichern. Es wird ja schon geschaut, ob der Mountpoint existiert und wenn nicht wird abgebrochen (?). Ich hätte in diesem Fall gern eine Meldung: “Backupziel nicht angeschlossen. Bitte jetzt mounten. [Wiederholen] [Abbrechen]” Möglich?

Diesen Beitrag zitieren

Avatar

Janek

30. Juni 2011 um 11:21

Zitat Paul :

1. Habe ich richtig verstanden: Bei der ersten Ausführung werden alle Daten kopiert, ab dann nur noch die geänderten Dateien. Gelöschte und alte Versionen von Dateien kommen in ein Verzeichnis mit dem jeweiligen Backupdatum. Es besteht sozusagen eine Versionierung. Korrekt?

Hallo Paul,

ob auch neben den gelöschten Dateien auch geänderte Dateien in das Verzeichnis “Geloeschte Dateien” kopiert werden, wusste ich ehrlich gesagt gar nicht mehr ganz genau. Habe aber gerade einen kleinen Test gemacht und es ist offenbar der Fall.
Eine Snapshot-Funktion, mit der sich sozusagen der Zustand eines bestimmten Tages wiederherstellen lässt, ist es aber dennoch nicht. Die Funktion ist eher dafür gedacht, einzelne Dateien, die versehentlich gelöscht wurden, wiederherzustellen.

Wenn du eine ausgefeiltere Versionierung möchtest, solltest du dir mal rdiff-backup anschauen.

Hier mal ein Skript von mir, dass derzeit auf einem kleinen Server läuft und ein Verzeichnis meines Notebooks sichert (verwende daher das in diesem Blogpost veröffentlichte Skript nicht mehr). Es müsste allerdings erst noch an deine Bedürfnisse angepasst werden.

#!/bin/bash
 
# = = Profil 1  = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
   title[1]="Dell Multimedia-Backup"
     arg[1]="dm"
 max_age[1]="3"
 
src_user[1]="janek"
src_host[1]="192.168.178.26"
 
# on directory per line
src_dirs[1]="/multimedia"
 
# Destination
 bak_dir[1]="/media/extern/rdiff-backup"
 
# List files and directories to exclude (one per line)
# tip: specify files to include by adding "+" in front of the line
  ex_lst[1]="**lost+found
**.Trash*
"
 
IFS="
"
 
[ "$1" == "" ] && echo "ERROR: missing argument" && exit 1
 
# readout arrays
for i in $(seq ${#arg[*]}); do	# number of 
  if [[ "${arg[$i]}" == "$1" ]]; then
	TITLE="${title[$i]}"
	ARG="${arg[$i]}"
	MAX_AGE="${max_age[$i]}"
 
	SRC_USER="${src_user[$i]}"
	SRC_HOST="${src_host[$i]}"
	SRC_HOSTNAME="$(ssh $SRC_USER@$SRC_HOST -C hostname || exit 1)"
 
	SRC_DIRS="${src_dirs[$i]}"
	BAK_DIR="${bak_dir[$i]}"
	EX_LST="${ex_lst[$i]}"
  fi
done
 
 
for SRC_DIR in $SRC_DIRS; do
  [ "$SRC_HOSTNAME" == "" ] && echo "ERROR: $SRC_HOSTNAME=$SRC_HOSTNAME" && exit 1
 
  DST_DIR="$BAK_DIR/${SRC_HOSTNAME}$SRC_DIR"
 
  echo
  echo "= = = = = = = = = = = = = = = = ="
  echo "TITLE         $TITLE"
  echo "ARG           $ARG"
  echo "MAX_AGE       $MAX_AGE"
  echo
  echo "SRC_USER      $SRC_USER"
  echo "SRC_HOST      $SRC_HOST"
  echo "SRC_DIR       $SRC_DIR"
  echo
  echo "BAK_DIR       $BAK_DIR"
  echo "DST_DIR       $DST_DIR"
  echo "EX_LST        $EX_LST"
  echo "= = = = = = = = = = = = = = = = ="
  echo
 
  # Break script if external harddrive is not mounted
  mount | grep $(dirname $BAK_DIR) > /dev/null || { echo "ERROR: HDD not mounted in $(dirname $BAK_DIR)" && exit 1 ;}
  [ ! -d "$DST_DIR" ] && mkdir -vp "$DST_DIR"
 
 
  # perform backup
  echo "$EX_LST" | rdiff-backup -v8 --print-statistics --exclude-globbing-filelist-stdin $SRC_USER@$SRC_HOST::$SRC_DIR $DST_DIR
done

2. Ich möchte auf eine externe Festplatte sichern. Es wird ja schon geschaut, ob der Mountpoint existiert und wenn nicht wird abgebrochen (?).

Wenn du in der Konfiguration einen Mountpoint angibst (MOUNT="/media/Meine externe Festplatte") wird zu Beginn geprüft, ob die Festplatte eingebunden ist. Falls dies nicht der Fall sein sollte, wird mit einer entsprechenden Fehlermeldung abgebrochen.

Gruß Janek

Diesen Beitrag zitieren

Avatar

Paul

30. Juni 2011 um 15:45

Zitat Janek :

ob auch neben den gelöschten Dateien auch geänderte Dateien in das Verzeichnis “Geloeschte Dateien” kopiert werden, wusste ich ehrlich gesagt gar nicht mehr ganz genau. Habe aber gerade einen kleinen Test gemacht und es ist offenbar der Fall.

Das reicht mir aus. Man nehme an: ich bearbeite eine Datei täglich und das Backup läuft ebenfalls täglich, dann hätte ich also von jedem Tag eine Version der Datei…

Wenn du eine ausgefeiltere Versionierung möchtest, solltest du dir mal rdiff-backup anschauen.

Die Versionierung mit rdiff benötigt dann beim Aufrufen einer bestimmten Version der Datei zwingend die Software, oder?

Wenn du in der Konfiguration einen Mountpoint angibst (MOUNT="/media/Meine externe Festplatte") wird zu Beginn geprüft, ob die Festplatte eingebunden ist. Falls dies nicht der Fall sein sollte, wird mit einer entsprechenden Fehlermeldung abgebrochen.

Gut. Ich will das ganze über Cron laufen lasse und da wäre es doof, wenn das Backup ständig abbricht, weil die Festplatte nicht gemountet ist. Stattdessen fände ich eine Meldung ala: “Backupziel nicht angeschlossen. Bitte jetzt mounten. [Wiederholen] [Abbrechen]” sinnvoll. Wie ist das möglich?

Diesen Beitrag zitieren

Avatar

Chrische

19. Juli 2011 um 20:38

Super Script! Vielen dank, einfacher gehts ja fast nicht.

Diesen Beitrag zitieren

Avatar

chefchiller

1. September 2011 um 20:04

Hola,
bekomme beim Startversuch des Scripts folgenden Fehler

chef@HermesII:~/Downloads$ sh backup-321tux.sh -pn
backup-321tux.sh: 34: Syntax error: "(" unexpected

Debian 11.04

jemand ne Ahnung ?

Bearbeitet von Janek (8. Sept. 2011): Codeblock eingefügt.

Diesen Beitrag zitieren

Avatar

Janek

8. September 2011 um 19:38

Zitat chefchiller :

bekomme beim Startversuch des Scripts folgenden Fehler

chef@HermesII:~/Downloads$ sh backup-321tux.sh -pn
backup-321tux.sh: 34: Syntax error: "(" unexpected

Hallo checfchiller,

für die Funktion in Zeile 34 gibt es verschiedene Schreibweisen. Du könntest das einleitende Wort function oder die beiden Klammern () entfernen. Wenn du damit erfolgreich bist, müsste der Fehler beim erneuten Ausführen des Skriptes in einer anderen Zeile auftreten, da mehrere Funktionen verwendet werden.
Warum bei dir der Fehler auftritt und bei anderen nicht, ist mir allerdings selbst ein Rätsel.

Gruß Janek

Diesen Beitrag zitieren

Avatar

Stefan

2. Oktober 2011 um 12:01

Ich habe mal einen neuen Parameter (-d) eingebaut, mit dem dann alte Backups entfernt werden. der Parameter erwartet eine Zahl als Argument (-d 120) um z.B. Backups älter als 120 Tage zu löschen. Schau dir mal das Skript an. Es ist wegen dem rm aber mit Vorsicht zu genießen.

#!/bin/bash
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#                                                                                       #
# = = = = = = = = = = = = = = = = = = RSYNC BACKUP  = = = = = = = = = = = = = = = = = = #
#                                                                                       #
# Author:   JaiBee, http://www.321tux.de                                                #
# Date:     2011-01-02                                                                  #
# Version:  0.98                                                                        #
# License:  Creative Commons "Namensnennung-Nicht-kommerziell-                          #
#           Weitergabe unter gleichen Bedingungen 3.0 Unported "                        #
#           [ http://creativecommons.org/licenses/by-nc-sa/3.0/deed.de ]                #
#                                                                                       #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
# Dieses Skript sichert / synchronisiert Verzeichnisse mit rsync.
# Dabei können beliebig viele Profile konfiguriert oder die Pfade direkt an das Skript übergeben werden.
# Eine kurze Anleitung kann mit der Option -h aufgerufen werden.
 
# WICHTIG: alle Pfadangaben müssen _ohne_ abschließenden Slash (/) angegeben werden!
#set -x
 
############################### ALLGEMEINE KONFIGURATION ################################
 
# RSYNC_OPT    Optionen für rsync; Verzeichnisse müssen und dürfen nicht angegeben werden
#
# MOUNT        [optional] Einhängepunkt der externen Festplatte
#              vor dem Backup wird überprüft, ob die externe Festplatte eingebunden ist
#
# BAK_DIR      Ordner, in den gelöschte Dateien kopiert werden (--backup-dir=)
#              (die Variable $TARGET, in der das Zielverzeichnis gespeichert ist, ist hierbei nützlich)
 
NOTIFY=echo # echo oder notify-send - echo bei Systemen ohne grafische Benutzeroberfläche
RSYNC_OPT="-savPbh --delete --numeric-ids --stats"
MOUNT="/mnt/POPPSTAR"
function func_bak_dir(){
  BAK_DIR="$TARGET/Geloeschte Dateien/$(date +%F)"
  #BAK_DIR="${TARGET///ROOTFS/}/Geloeschte Dateien/$(date +%F)/"
}
 
############################### KONFIGURATION DER PROFILE ###############################
 
# title[n]     Bezeichnung des Profils; wird u.a. in der Hilfe angezeigt
#
# arg[n]       Argument, mit dem das jeweilige Profil gestartet wird (-p arg[n])
#
# source[n]    Quellverzeichnis(se) (abschließender Slash optional möglich)
#              WICHTIG: Pfadangaben, die Leerzeichen enthalten, müssen von " umschlossen werden!
#                       Z.B. "/Verzeichnis mit Leerzeichen/"
#
# target[n]    Zielverzeichnis
#
# log[n]       [optional] Logdatei, in der die Ausgabe von rsync gespeichert wird
#
# exfrom[n]    temporäre Datei (Standard: $(mktemp -t "tmp.rsync.XXXX")); muss nicht geändert werden
#
# rsync_opt[n] [optional] Optionen für rsync, wenn nicht die Optionen aus $RSYNC_OPT (s.o.) verwendet werden sollen
#
# cat > "${exfrom[1]}" < "${exfrom[1]}" < "${exfrom[2]}" < "${exfrom[n]}" < $TITLE	|	arg[n]    -> $ARG		|	rsync_opt[n] -> $RSYNC_OPT	|	log[n]    -> $LOG
# source[n] -> $SOURCE	|	target[n] -> $TARGET	|	exfrom[n]    -> $EXFROM
 
###################################### FUNKTIONEN #######################################
 
# Wird in der Konsole angezeigt, wenn eine Option nicht angegeben oder definiert wurde
function func_help(){
	echo -e "Aufruf: 33[1m$0 33[34m-p33[0m 33[1;36mARGUMENT33[0m [33[1;34m-p33[0m 33[1;36mARGUMENT33[0m]"
	echo -e "        33[1m$0 33[34m-m33[0m 33[1;36mQUELLE(n)33[0m 33[1;36mZIEL33[0m"
	echo
	echo -e "33[4merforderlich33[0m"
	for i in $(seq ${#arg[*]});	do echo -e "  33[1;34m-p33[0m 33[1;36m${arg[$i]}33[0m	Profil "${title[$i]}""; done
	echo -e "odern  33[1;34m-a33[0m	alle Backup-Profile"
	echo -e "odern  33[1;34m-m33[0m	Verzeichnisse manuell angeben"
	echo
	echo -e "33[4moptional33[0m"
	echo -e "  33[1;34m-s33[0m	PC nach Beendigung automatisch herunterfahren (benötigt u.U. Root-Rechte)"
	echo -e "  33[1;34m-d33[0m 33[1;36mx33[0m	Alte Backup-Dateien die älter als x Tage sind löschen"
	echo -e "  33[1;34m-h33[0m	Hilfe anzeigen"
	echo
	echo -e "33[4mBeispiele33[0m"
	echo -e "  33[32mProfil "${title[2]}"33[0m starten und den Computer anschließend 33[31mherunterfahren33[0m:"
	echo -e "	$0 33[32m-p${arg[2]}33[0m 33[31m-s33[0mn"
	echo -e "  33[33m"/tmp/Quelle1/"33[0m und 33[35m"/Leer zeichen2/"33[0m mit 33[36m"/media/extern"33[0m synchronisieren; anschließend 33[31mherunterfahren33[0m:"
	echo -e "	$0 33[31m-s33[0;4mm33[0m 33[33m/tmp/Quelle133[0m 33[4m"33[0;35m/Leer zeichen233[0;4m"33[0m 33[36m/media/extern33[0m"
 
	func_exit
}
 
function func_exit(){
	rm ${exfrom[*]}
	exit 1
}
 
function func_settings(){
	if [[ "$PROFIL" != "customBak" ]]; then
		# Benötigten Werte aus dem Array holen
		for i in $(seq ${#arg[*]}); do								# Anzahl der vorhandenen Profile ermitteln
			if [[ "${arg[$i]}" == "$PROFIL" ]]; then				# wenn das gewünschte Profil gefunden wurde
				TITLE="${title[$i]}";		ARG="${arg[$i]}"
				SOURCE="${source[$i]}";		TARGET="${target[$i]}"
				LOG="${log[$i]}";			EXFROM="${exfrom[$i]}"
				[[ "${rsync_opt[$i]}" != "" ]] && RSYNC_OPT="${rsync_opt[$i]}"
			fi
		done
	fi
	[ "$SOURCE" == "/" ] && TARGET="${TARGET}/ROOTFS"				# Workaround für "/"
}
 
function del_old_backup() {
	# Verzeichnisse älter als $DEL_OLD_BACKUP tage löschen
	echo "Lösche alte Backup-Dateien aus ${1}, die älter als ${DEL_OLD_BACKUP} Tage sind..."
	find "${1}" -maxdepth 1 -type d -mtime +$DEL_OLD_BACKUP -print0 | xargs -0 rm -rf
}
 
######################################### START #########################################
 
# Wenn eine grafische Oberfläche vorhanden ist, wird u.a. "notify-send" für Benachrichtigungen verwendet, ansonsten immer "echo"
NOTIFY="echo"
[ -n "$DISPLAY" ] && NOTIFY="notify-send"
 
tty -s && clear
echo -e "33[44m 33[0m33[1m RSYNC BACKUP33[0mn33[44m 33[0m 2011 by JaiBee, http://www.321tux.de/n";
 
while getopts ":p:am:sd:h" opt
do
	case $opt in
		p) for i in "$OPTARG"; do P="$P $i"; done ;;	# bestimmte(s) Profil(e)
		a) P=${arg[*]} ;;								# alle Profile
		m) # eigene Verzeichnisse an das Skript übergeben
			for i in "$@"; do 							# letzte Pfad als Zielverzeichnis
				[ -d "$i" ] && TARGET="$i";
			done
			for i in "$@"; do							# alle übergebenen Verzeichnisse außer $TARGET als Quelle
				[[ -d "$i" && "$i" != "$TARGET" ]] && SOURCE="$SOURCE "$i""
			done
			TARGET="$(echo $TARGET | sed -e 's//$//')"	# Slash am Ende entfernen
			P="customBak";					TITLE="Custom Backup"
			LOG="$TARGET/$TITLE-log.txt";	MOUNT="" ;;
		s) SHUTDOWN=0 ;;								# Herunterfahren gewählt
		d) DEL_OLD_BACKUP=$OPTARG ;;		# Alte Backups-Dateien entfernen (Zahl entspricht Tage, die erhalten bleiben)
		h) func_help ;;									# Hilfe anzeigen
		?) echo -e "33[1;41m FEHLER 33[0;1m Option ungültig.33[0mn" && func_help ;;
	esac
done
 
# Sind die benötigen Programme installiert?
which rsync mktemp wall sed $NOTIFY > /dev/null || { echo "Sie benötigen die Programme rsync, mktemp, wall, sed und $NOTIFY zur Ausführung dieses Skriptes."; func_exit; }
 
# wenn $P leer ist, wurde die Option -p oder -a nicht angegeben
[[ -z "$P" ]] && echo -e "33[1;41m FEHLER 33[0;1m es wurde kein Profil gewählt33[0mn" && func_help
 
# folgende Zeile auskommentieren, falls zum Herunterfahren des Computers Root-Rechte erforderlich sind
#[[ "$SHUTDOWN" == "0" && "$(whoami)" != "root" ]] && echo -e "33[1;41m FEHLER 33[0;1m Zum automatischen Herunterfahren sind Root-Rechte erforderlich.33[0mn" && func_help
 
[ "$SHUTDOWN" == "0" ] && echo -e "  33[1;31mDer Computer wird nach Durchführung des Backups automatisch heruntergefahren!33[0m"
 
for PROFIL in $P; do
	func_settings
	func_bak_dir
 
	# /ROOTFS aus $BAK_DIR entfernen
	BAK_DIR="${BAK_DIR///ROOTFS/}"
 
	# wurden der Option -b gültige Argument zugewiesen?
	[[ "$PROFIL" != "$ARG" && "$PROFIL" != "customBak" ]] && echo -e "33[1;41m FEHLER 33[0;1m -p wurde nicht korrekt definiert.33[0mn" && func_help
 
	# Konfiguration zu allen gewählten Profilen anzeigen
	echo -e "  33[4mnKonfiguration von 33[1m$TITLE33[0m"
	echo -e "33[46m 33[0m Quellverzeichnis(se):33[1mt$SOURCE33[0mn33[46m 33[0m Zielverzeichnis:33[1mt$TARGET33[0m"
	echo -e "33[46m 33[0m Log-Datei:33[1mtt$LOG33[0m"
	if [[ "$PROFIL" != "customBak" ]]; then echo -e "33[46m 33[0m Exclude:"; sed 's/^/ttt/' $EXFROM ; fi
done
 
for PROFIL in $P; do
	func_settings
 
	# ist die Festplatte eingebunden?
	[[ "$TARGET" == "$MOUNT"* && ! $(mount | grep "$MOUNT") ]] && echo -e "33[1;41m FEHLER 33[0;1m Die Festplatte ist nicht eingebunden.33[0m ("$MOUNT")" && func_exit
 
	# ggf. Zielverzeichnisse erstellen
	[ ! -d "$TARGET" ]  &[ ! -d "$BAK_DIR" ] &echo -e "n33[1m$TITLE wird in 5 Sekunden gestartet.33[0m"
	echo -e "33[46m 33[0m Zum Abbrechen [Strg] + [C] drückenn33[46m 33[0m Zum Pausieren [Strg] + [Z] drücken (Fortsetzen mit "fg")n"
	sleep 5
	$NOTIFY "Backup startet (Profil: "$TITLE")"
 
	# Backup mit rsync starten
	eval rsync $RSYNC_OPT --log-file="$LOG" --exclude-from="$EXFROM" --backup-dir="$BAK_DIR" $SOURCE "$TARGET"
 
	# Funktion zum Löschen alter Backups aufrufen
	[ -n "$DEL_OLD_BACKUP" ] && del_old_backup "$TARGET/Geloeschte Dateien"
 
	echo -e "ann33[1m$TITLE wurde abgeschlossen33[0mnWeitere Informationen sowie Fehlermeldungen sind in der Datei "$LOG" gespeichert.n"
done
 
rm ${exfrom[*]}
 
# ggf. Herunterfahren
if [ "$SHUTDOWN" == "0" ] ; then
	# Möglichkeit, das automatische Herunterfahren noch abzubrechen
	$NOTIFY "Backup(s) abgeschlossen. ACHTUNG: Der Computer wird in 5 Minuten heruntergefahren. Führen Sie "kill -9 $(ps -A | grep -m1 "$(basename "$0")" | cut -d " " -f2)" aus, um das Herunterfahren abzubrechen."
	sleep 1
	echo "This System is going DOWN for System halt in 5 minutes! Run "kill -9 $(ps -A | grep -m1 "$(basename "$0")" | cut -d " " -f2)" to  cancel shutdown." | wall
	echo -en "a33[1;41m ACHTUNG 33[0m Der Computer wird in 5 Minuten heruntergefahren.nn"
	echo -e "Bitte speichern Sie jetzt alle geöffneten Dokumente oder drücken Sie 33[1m[Strg] + [C]33[0m,nfalls der Computer nicht heruntergefahren werden soll.n"
	sleep 5m
	# verschiedene Befehle zum Herunterfahren mit Benutzerrechten [muss evtl. an das eigene System angepasst werden!]
	# Alle Systeme mit HAL || GNOME DBUS || KDE DBUS || GNOME || KDE
	# Root-Rechte i.d.R. erforderlich für "halt" und "shutdown"!
	dbus-send --print-reply --system --dest=org.freedesktop.Hal /org/freedesktop/Hal/devices/computer org.freedesktop.Hal.Device.SystemPowerManagement.Shutdown || 
	dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.RequestShutdown || 
	dbus-send --print-reply --dest=org.kde.ksmserver /KSMServer org.kde.KSMServerInterface.logout 0 2 2 || 
	gnome-power-cmd shutdown || dcop ksmserver ksmserver logout 0 2 2 || 
	halt || shutdown -h now
else
	$NOTIFY "Backup(s) abgeschlossen."
fi

Bearbeitet von Janek am 2. Okt. 2011: Code-Tag korrigiert. Mit folgender Syntax können Bash-Codes eingefügt werden (die Rauten # und Leerzeichen vor “pre” müssen entfernt werden!):

< #pre lang="bash">
echo "Hallo"
< #/pre>

Diesen Beitrag zitieren

Avatar

Daniel

14. Oktober 2011 um 01:14

Hallo Janek,

echt SUPER!! Vielen Dank für deine investierte Arbeitszeit und die Veröffentlichung online! Das Script spart eine Menge Zeit und hilft enorm!!

Viel Erfolg weiterhin.

Daniel

Diesen Beitrag zitieren

Avatar

Uwe S

2. November 2011 um 18:32

Hallo Janek,

ich habe mir mal dein Scripts heruntergeladen und source & target modifiziert.

Leider bekomme ich bei der Ausführung aber immer ein:

root@uwe-ubuntu-3:/root# sh backup-321tux.sh -ph
backup-321tux.sh: 34: Syntax error: "(" unexpected

Mache ich irgendwas falsch? Ubuntu 11.10 server

Gruss Uwe

Bearbeitet von Janek (2.11.2011): pre-Tag eingefügt

Diesen Beitrag zitieren

Avatar

Janek

2. November 2011 um 18:39

Zitat Uwe S :

Leider bekomme ich bei der Ausführung aber immer ein:

root@uwe-ubuntu-3:/root# sh backup-321tux.sh -ph
backup-321tux.sh: 34: Syntax error: “(” unexpected

Hallo Uwe,

du hast vermutlich nichts falsch gemacht. Von diesem Problem hat schon einmal jemand berichtet und ich vermute, dass sich die Syntax in einer neueren Version der Bash geändert hat. Probiere mal diesen Vorschlag aus und berichte uns anschließend bitte, ob es damit funktioniert.

Viele Grüße
Janek

EDIT: Da fällt mir gerade noch etwas ein: starte das Skript mal ohne “sh”, also

root@uwe-ubuntu-3:/root# ./backup-321tux.sh -ph

Diesen Beitrag zitieren

Avatar

Stefan

3. November 2011 um 08:13

Möglicherweise ist es immer noch so, dass unter ubunu “dash” als Shell dient. Mach mal ein “ls -l /bin/sh” um zu sehen ob es auf bash zeigt. Wenn nicht, dann im Skript mal die ertsze Zeile ändern in “#!/bin/bash”

Das habe ich dazu gefunden: http://ubuntuforums.org/showpost.php?p=3006552&postcount=2

Diesen Beitrag zitieren

Avatar

Uwe S

3. November 2011 um 10:29

Zitat Janek :

Viele Grüße
Janek

EDIT: Da fällt mir gerade noch etwas ein: starte das Skript mal ohne “sh”, also

root@uwe-ubuntu-3:/root# ./backup-321tux.sh -ph

Hallo Janek, genau das wars!

Ohne “sh” am Anfang läuft alles wunderbar!

Dank Euch allen für Eure schnellem Antworten!

Gruss Uwe

Diesen Beitrag zitieren

Avatar

ch

8. November 2011 um 21:02

Hy!

Zuerst mal Kompliment! Tolles Script ist wirklich einfach zu verstehen!

Habe nur ein Problem:

Ich habe mittels davfs2 meinen box.net Cloud-Speicher auf meinen Server unter /media/box.net gemountet. Das klappt alles schon ganz gut, auch wenn der Server neustartet, wird die Partition richtig gemountet.

Wenn ich nun aber das Script starte, bekomme ich folgenden Fehlermeldung:

 FEHLER  Die Festplatte ist nicht eingebunden. ("/media/box.net/domain")

Zusätzlich wird mir folgendes vom Script ausgegeben:

Konfiguration von domain-server-backup
  Quellverzeichnis(se): /var/www /var/local/subversion /home /boot /etc
  Zielverzeichnis:      /media/box.net/domain/backup
  Log-Datei:            /media/box.net/domain/backup/domain-server-backup-log.txt
  Exclude:

Woran kann das liegen?

Bearbeitet von Janek (9.11.2011): pre-Tag eingefügt

Diesen Beitrag zitieren

Avatar

Janek

9. November 2011 um 00:16

Hallo ch,

um zu testen, ob eine Festplatte eingebunden ist, durchsucht das Skript die Ausgabe des Befehls mount nach dem im Skript festgelegten Mountpoint. Ist dies nicht der Fall, wird die entsprechende Fehlermeldung ausgegeben und das Skript abgebrochen.

Ich weiß nicht, wie sich davfs2 verhält, aber ich vermute, dass “/media/box.net/” nicht angezeigt wird, wenn du folgendes im Terminal eingibst:

mount

Wenn ich mit meiner Vermutung richtig liegen, kannst du den Mount-Check mit “#” auskommentieren (wird also nicht mehr beachtet) oder du schaust, wie sich mit davfs2 herausfinden lässt, ob ein Verzeichnis eingebunden ist (und integrierst das dann im Skript an der entsprechenden Stelle).

Viele Grüße
Janek

Diesen Beitrag zitieren

Avatar

Stefan

9. November 2011 um 08:19

Oder einfach mal in der allgemeinen Konfiguration MOUNT= leer lassen oder auskommentieren. Dann sollte auch keine Prüfung erfolgen.

Diesen Beitrag zitieren

Avatar

ch

9. November 2011 um 09:18

Guten Morgen!

Danke für die schnellen Antworten :-) Habe mit folgenden Befehlt überprüft ob das externe Verzeichnis richtig eingehangen ist:


user@Ubuntu-1104-natty-64-minimal:/$ mount -t davfs

und bekomme dann folgendes raus


https://www.box.net/dav on /media/box.net type davfs (rw,nosuid,nodev,_netdev)

also anscheinend ist das Verzeichnis doch richtig eingebunden. Hab es trotzdem mal auskommentiert, danach funktioniert das Ausführen des Scripts.

Nur habe ich jz den nächsten Fehler, bestimmte Verzeichnisse werden einfach mit der Meldung Permission denied übersprungen und nicht synchronisiert.

Ich führe das Script als Admin-User aus (root ist gelockt) wie kann ich es erzwingen, dass trotzdem alle Verzeichnisse und Dateien (auch mit Dateirechten wie z.B. tomcat oder www-data) kopiert werden?

Danke und beste Grüße!

Diesen Beitrag zitieren

Avatar

ch

10. November 2011 um 18:14

Zitat ch :

Nur habe ich jz den nächsten Fehler, bestimmte Verzeichnisse werden einfach mit der Meldung Permission denied übersprungen und nicht synchronisiert.

Ich führe das Script als Admin-User aus (root ist gelockt) wie kann ich es erzwingen, dass trotzdem alle Verzeichnisse und Dateien (auch mit Dateirechten wie z.B. tomcat oder www-data) kopiert werden?

Danke und beste Grüße!

… das Problem mit den Mountpoint habe ich nun gelöst. Nur bleibt jz noch das Verzeichnis, dass kaum Dateien gesichert werden der Großteil der Daten wird mit der Meldung

Permission denied (13) bzw. Function not implemented (38)

Diesen Beitrag zitieren

Avatar

Janek

10. November 2011 um 19:09

Zitat ch :

… das Problem mit den Mountpoint habe ich nun gelöst. Nur bleibt jz noch das Verzeichnis, dass kaum Dateien gesichert werden der Großteil der Daten wird mit der Meldung

Permission denied (13) bzw. Function not implemented (38)

Hallo ch,

das Skript bzw. rsync sind bereits so konfiguriert, dass alle Dateien inkl. der Berechtigungen kopiert werden. Es handelt sich daher nicht um einen Fehler im Skript, sondern liegt an der Konfiguration deines Systems. Du kannst es vielleicht mal mit der rsync-Option --fake-super probieren, wobei ich nicht wirklich weiß, ob das ein passender Ansatz ist.

Ansonsten kann ich dir nur empfehlen, weiter im Internet zu recherchieren bzw. in einem Forum nachzufragen. Wenn du die richtige Einstellung für rsync gefunden hast, kannst du sie ohne weiteres im Skript integrieren.

Viel Erfolg,
Gruß Janek

Diesen Beitrag zitieren

Avatar

EliasMH

27. November 2011 um 17:18

Wunderbar, zeit gespart, und doch verloren. So ist das, wenn man sich in den code von jemand anderem einarbeitet und gefallen an der sache findet. ;-) Arbeite gerade an einer snapshot lösung.

Diesen Beitrag zitieren

Backup-Skript - Stefan's Blog

12. Dezember 2011 um 15:47

[...] Komfortables Backup-Skript (rsync) | 321tux.de [...]

Backup-Skript mit FTP-Quelle - Stefan's Blog

7. Januar 2012 um 13:12

[...] habe das Backup-Skript von Komfortables Backup-Skript (rsync) | 321tux.de um eine weitere Funktion erweitert. Diesmal ging es mir darum, einen FTP-Server als Quelle [...]

Kommentar schreiben

Erlaubte Tags:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

Die nofollow-freien Links richten sich in erster Linie an Blogger und Betreiber von privaten Homepages. Beiträge, die im Feld "Homepage" eine kommerziellen Internetseite enthalten, werden daher meist als Spam eingestuft, da davon ausgegangen werden muss, dass diese nur dem Linkaufbau dienen sollen.

Abonnieren ohne einen Kommentar abzugeben

Über 321tux.de

Hier bloggt Janek (20 Jahre, Schüler) aka JaiBee v.a. über Themen rund um Ubuntu und GNU/Linux, sowie vereinzelt auch über WordPress und sonstigen Themen des Internets.

Twitter Identi.ca Identi.ca

Google+

Beliebte Beiträge

Shell-Button

Panel Applets Button

EncFS-Button

Lucid-Button

Grafiken erstellt mit GIMP