Backup am Mac mit Automator, Shell Skript und rsync

Eine Datensicherung von einem Mac zu openmediavault lässt sich mit Automator, Shell Skripten und rsync (fast) automatisieren. Ein Client ist dafür nicht notwendig.

Backup unverzichtbar aber doch irgendwie lästig, oder?

Das Sichereungsprozedere lässt sich mit ein mit

  • Automator
  • AppleScript
  • Shell Skripten

sehr gut (fast) automatisieren.

Hört sich kompliziert an, ist es aber nicht.

Das Schaubild zeigt grafisch, wie der gesamte Prozess aussieht.

MacOS, Automator, rsync, openmediavault
MacOS, Automator, rsync, openmediavault

Als NAS im eigenen Netzwerk verwende ich für diese Anleitung ein openmediavault. Es läuft auf einem Raspberry Pi 4 mit 2 GB RAM. Am Pi hängen ein paar externe Festplatten, die bereits konfiguriert und für meinen Benutzer freigegeben worden sind. (Die Konfiguration von openmediavault ist nicht Teil dieser Anleitung.)

Mehr Infos zum freien NAS gibt es auf der Themenseite zu ➡ openmediavault NAS hier im Blog.

Das hier vorgestellte Setup funktioniert sehr zuverlässig. openmediavault ist meiner Meinung nach eine sehr gute und zuverlässige NAS-Lösung zu kommerziellen Anbietern Synology und QNAP und ist in Verbindung mit dem kleinen Raspberry Pi eine kostengünstige Alternative. Zudem sehr flexibel, da sich sehr viele unterschiedliche Festplatte und USB-Sticks an dem kleinen Einplatinenrechner anschließen lassen.

Auf dem Mac lassen sich mit Automator lokale Bash-Skripte aufrufen und damit beliebige Befehle und Operationen auf dem Mac ausführen.


ACHTUNG

In diesem Beispiel wird die openmediavault-Freigabe nicht durch Automator, AppleScript oder das Shell Skript beim Mac eingebunden. Das muss manuell durch den Benutzer erfolgen.
Am Einfachsten funktioniert das Einbinden von openmediavault-Freigaben mit Finder.


Das AppleScript ist schnell erstellt. Die Ausgabe von rsync soll auch in der Application iTerm angezeigt werden. Wenn du ein anderes Terminal verwendest, dann musst du den Applikationsnamen ändern.

Das Shell Skript mit den rsync-Befehlen ist im Verzeichnis ~/Documents/rsync abgelegt.

Der Name des Bash Skript lautet backup-openmediavault-all.sh

Im nächsten Schritt wird in das Verzeichnis ~/Documents/rsync gewechselt, mit dem Befehl cd.

Zum Schluss wird das Shell Skript backup-openmediavault-all.sh aufgerufen.

tell application "iTerm"
    set newWindow to (create window with default profile)
    tell current session of newWindow
        write text "clear"
        write text "cd ~/Documents/rsync; ls"
        write text "./backup-openmediavault-all.sh"
        write text "exit"
    end tell
end tell

Shell Script für rsync backup-openmediavault-all.sh

In diesem Beispiel gibt es drei Shell Skripte die unterschiedliche Funktionen erfüllen.

  • backup-openmediavault-all.sh = Hauptskript, dort werden Variablen, Verfügbarkeit der openmediavault-Freigaben abgefragt und die Unter-Skripte aufgerufen
  • backup-openmediavault-documents.sh = Unter-Skript – enthält die rsync-Befehle zum Sichern des Dokumenten-Verzeichnisses
  • backup-openmediavault-bilder.sh = Unter-Skript – enthält die rsync-Befehle zum Sichern des Bilder-Verzeichnisses

Wie das Ganze funktioniert und wie die Variablen vom Hauptskript an die beiden Unterskripte übergeben werden, habe ich in diesem Artikel beschrieben ➡ https://strobelstefan.org/2022/02/27/shellskript-variablen-an-andere-skripte-uebergeben/


Gib mir gerne einen Kaffee ☕ aus!

Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕ ausgeben.

PayPal Logo


liberapay.com/strobelstefan.org


Kaffee via Bitcoin

bc1qfuz93hw2fhdvfuxf6mlxlk8zdadvnktppkzqzj


Das Hauptskript backup-openmediavault-all.sh

Das Shell Skript backup-openmediavault-all.sh kann so aussehen:

#!/usr/bin/env bash


###################################
# Variables
###################################

# Hostname
echo "Host = $(hostname)"

# Script name
SCRIPTNAME=$(basename -- "$0")
echo "SCRIPTNAME = ${SCRIPTNAME}"

# Location of your log file on your Mac
LOGFILE="${HOME}/rsync/openmediavault-backup-rsync-$(date +%Y-%m-%d_%H-%M-%S).log"
exec 1> ${LOGFILE}

if test -f "${LOGFILE}"
	then
		echo "++++++++++++++++++++++++++" >&1
		echo "$(date +%Y-%m-%d_%H-%M-%S) - Start ${SCRIPTNAME} on $(hostname)" >&1
		echo "++++++++++++++++++++++++++" >&1
		echo "" >&1
		echo "$(date +%Y-%m-%d_%H-%M-%S) - Log File already exists!" >&1
		echo "$(date +%Y-%m-%d_%H-%M-%S) - Log File location: ${LOGFILE}" >&1
	else
		touch ${LOGFILE}
		echo "++++++++++++++++++++++++++" >&1
		echo "$(date +%Y-%m-%d_%H-%M-%S) - Start ${SCRIPTNAME} on $(hostname)" >&1
		echo "++++++++++++++++++++++++++" >&1
		echo "" >&1
		echo "$(date +%Y-%m-%d_%H-%M-%S) - Log File newly created!" >&1
		echo "$(date +%Y-%m-%d_%H-%M-%S) - Log File location: ${LOGFILE}" >&1
fi

# PWD = Script location  = Mac
SCRIPTPWD="${HOME}/Documents/rsync/"

# Mount point for network share on local client = Mac
LOCAL_DESTINATION="${HOME}/Desktop"

# Name of Network Share Folder
declare -a REMOTE_MOUNTS=(Sicherung-benutzer)

# Backup storage = Mount Point
BACKUPSTORAGE="/Volumes/Sicherung-benutzer"

# Backup directory on MAC
# on local client for "rsync --delete" option
# folder on MAC where deleted files gets stored by rsync
BACKUPDIRECTORY="${HOME}/rsync/"

# Remote file server = openmediavault
# IP Address, URL, etc. 
REMOTE_SERVER='192.168.178.220'

# Remote user = openmediavault
REMOTE_USER='benutzername'


echo "" >&1
echo "----" >&1
echo "SCRIPTPWD = ${SCRIPTPWD}" >&1
echo "" >&1
echo "REMOTE_SERVER = ${REMOTE_SERVER}" >&1
echo "REMOTE_USER = ${REMOTE_USER}" >&1
echo "REMOTE_MOUNTS = ${REMOTE_MOUNTS}" >&1
echo "Remote folder off network share " >&1
echo "" >&1
echo "LOCAL_DESTINATION = ${LOCAL_DESTINATION}" >&1
echo "Folder for mount point on client for network share " >&1
echo "" >&1
echo "BACKUPSTORAGE = ${BACKUPSTORAGE}" >&1
echo "Shared folder of network share where files are copied " >&1
echo "" >&1
echo "BACKUPDIRECTORY = ${BACKUPDIRECTORY}" >&1
echo "Folder where rsync --delete saves folders and files on local client" >&1
echo "----" >&1
echo "" >&1



###################################
# Check storage availability
###################################
# If network share is not pingable, script will stop

echo "$(date +%Y-%m-%d_%H-%M-%S) - Check ${REMOTE_SERVER} Availability - Send PING" >&1
echo "Storage Address = ${REMOTE_SERVER}" >&1

ping -c1 ${REMOTE_SERVER} >&1
if [ $? -eq 0 ]
  then 
    echo "$(date +%Y-%m-%d_%H-%M-%S) - ${REMOTE_SERVER} available - CONTINUE" >&1
  else
    echo "" >&1
    echo "$(date +%Y-%m-%d_%H-%M-%S) - ${REMOTE_SERVER} NOT available - STOPP Script" >&1
    echo "$(date +%Y-%m-%d_%H-%M-%S) - BACKUP FAILED" >&1
    
    open -a "Console" >&1
    sleep 15
    osascript -e 'tell application "Console" to quit'
    
    exit 1
fi

echo "" >&1 



###################################
# Check mount point availability and call subscripts
###################################
# This sections calls the subscripts
# - backup-openmediavault-documents.sh
# - backup-openmediavault-bilder.sh


if [ -d ${BACKUPSTORAGE} ]

then
    echo "Already mounted ${BACKUPSTORAGE}" >&1
    echo "$(date +%Y-%m-%d_%H-%M-%S) ${BACKUPSTORAGE} Mount Point Available - START Backup Scripts" >&1
    echo "" >&1
   
    /bin/bash ${SCRIPTPWD}backup-openmediavault-documents.sh "${LOGFILE}" "${BACKUPDIRECTORY}" "${BACKUPSTORAGE}"
    
    echo "" >&1
    
    /bin/bash ${SCRIPTPWD}backup-openmediavault-bilder.sh "${LOGFILE}" "${BACKUPDIRECTORY}" "${BACKUPSTORAGE}"
    
    open -a "Console" >&1
    sleep 15
    osascript -e 'tell application "Console" to quit'
    
else
    echo "Not mounted" >&1
    sleep 5
    echo "$(date +%Y-%m-%d_%H-%M-%S) ${BACKUPSTORAGE} not mounted - NO BACKUP" >&1
    
    open -a "Console" >&1
    sleep 15
    osascript -e 'tell application "Console" to quit'
    
    exit 2
fi

###################################
# Delete Old Files
###################################

echo "$(date +%Y-%m-%d_%H-%M-%S) - Remove Files Older Than 10 Days in backup directory ${BACKUPDIRECTORY}" >&1

#find ${BACKUPDIRECTORY}* -mtime +10 -exec rm -rf {} \; >&1

# Delete files older than
find ${BACKUPDIRECTORY}* -mtime +7 -exec rm -r {} \; >&1

# Delete empty folders
find ${BACKUPDIRECTORY}* -empty -type d -delete >&1

exit 0

Unter-Skript backup-openmediavault-documents.sh

Das erste Unter-Skript sichert das Dokumentenverzeichnis eures Macs.

#!/usr/bin/env bash


SCRIPTNAME=$(basename -- "$0")

echo "+++++" >&1
echo "SCRIPTNAME = ${SCRIPTNAME}" >&1
echo "+++++" >&1

echo "Passed Variables to ${SCRIPTNAME}:" >&1
echo "----" >&1
echo "LOGFILE = $1" >&1
echo "BACKUPDIRECTORY = $2" >&1
echo "BACKUPSTORAGE = $3" >&1

echo "" >&1


###################################
# Backup Folder Definition
###################################
echo "" >&1
echo "----" >&1
echo $(date +%Y-%m-%d_%H-%M-%S) " - Start rsync process - 1st Backup Folder" >&1

#Source patch - local client = Mac
SOURCE="${HOME}/Documents/"
echo "SOURCE = ${SOURCE}" >&1

#Target path on BACKUPSTORAGE = openmediavault
TARGET="$3/dokumente/"
echo "TARGET = ${TARGET}" >&1

#Exclude from RSYNC file
EXCLUDEFILE="${HOME}/Documents/rsync/rsync-macos-excludefile.txt"
echo "EXCLUDEFILE = ${EXCLUDEFILE}" >&1

#BACKUP Directory
# In dieses Verzeichnis werden alle Dateien kopiert die während des rsync-Laufs durch die Option --delete gelöscht werden.
# Diese Option erzeugt eine hohe Systemlast und eine sehr lange Laufzeit des Skripts
#BACKUPDIRECTORY="$2"
echo "BACKUPDIRECTORY = $2" >&1


rsync -avhbP --iconv=UTF8,UTF8-MAC --stats --delete --log-file=$1 --backup-dir=$2 ${SOURCE} ${TARGET}

echo "----" >&1

echo "${SCRIPTNAME} - Beendet"

sleep 15

exit 0


###################################
#Starts rsync Process From Source to Target
###################################
# Copies the files from Source to Target

#     -a fasst folgende Optionen zusammen:
#     -r kopiert Unterverzeichnisse
#     -l kopiert symbolische Links
#     -p behält Rechte der Quelldatei bei
#     -t behält Zeiten der Quelldatei bei,
#     -g behält Gruppenrechte der Quelldatei bei
#     -o behält Besitzrechte der Quelldatei bei (nur root)
#     -D behält Gerätedateien der Quelldatei bei (nur root)
#     -v: zeigt während des Synchronisierens alle ausgeführten Schritte an
#     -h: human readable
#     -c: aktiviert einen Dateivergleich, basierend auf Prüfsumme und nicht auf Größe und Zeitstempel. Die eigentliche Prüfsummenbildung dauert DEUTLICH länger als der Vergleich Größe und Änderungs-Zeitstempel; andererseits werden überflüssige Kopiervorgänge (z.B. bei nur geänderter Änderungszeit) vermieden.
#     -n: simuliert nur was passieren würde ("dry run")
#     -b: sorgt dafür, dass durch die Option --delete gelöschte sowie alle veränderten Objekte gesichert werden (--backup-dir=)
#     -P: aktiviert folgende Optionen:
#     --progress Fortschrittsanzeige beim Transfer anzeigen
#     --partial Fortsetzung des Transfers bei Abbruch
#     --stats: zeigt einen ausführlicheren Bericht am Ende einer Übertragung an.
#     --delete: vergleicht Quellverzeichnisse und Zielverzeichnisse und sorgt dafür, dass Dateien, die im Quellverzeichnis nicht (mehr) vorhanden sind, im Zielverzeichnis gelöscht werden. Dies kann dazu führen, dass man ungewollt Dateien löscht, die man aber noch in der Sicherung behalten möchte.
#     --ignore-existing: Überspringt die vorhandenen Daten und schreibt nur die neuen

# Sync mit einem Mac
# Umlaute produzieren Fehler bei rsync

# von Linux zu MAC
# --iconv=UTF8-MAC,UTF8

# von Mac zu Linux
#--iconv=UTF8,UTF8-MAC

# Dieser Abschnitt erklärt die Syntax von rsync
#sudo rsync -av --stats --delete --exclude ${EXCLUDE} --exclude ${EXCLUDE1} --exclude ${EXCLUDE2} --exclude ${EXCLUDE3} --exclude ${EXCLUDE4} ${SOURCE} ${TARGET} --log-file=$1

# Ohne Log Files
#sudo rsync -av --stats --exclude-from=${EXCLUDEFILE} --delete ${SOURCE} ${TARGET}


Gib mir gerne einen Kaffee ☕ aus!

Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕ ausgeben.

PayPal Logo


liberapay.com/strobelstefan.org


Kaffee via Bitcoin

bc1qfuz93hw2fhdvfuxf6mlxlk8zdadvnktppkzqzj


Unter-Skript backup-openmediavault-bilder.sh

Das zweite Unter-Skript sichert die Bilder-Verzeichnisse.

#!/usr/bin/env bash


SCRIPTNAME=$(basename -- "$0")
echo "SCRIPTNAME = ${SCRIPTNAME}"

echo "+++++" >&1
echo "SCRIPTNAME = ${SCRIPTNAME}" >&1
echo "+++++" >&1

echo "Passed Variables to ${SCRIPTNAME}:" >&1
echo "----" >&1
echo "LOGFILE = $1" >&1
echo "BACKUPDIRECTORY = $2" >&1
echo "BACKUPSTORAGE = $3" >&1

echo "" >&1


###################################
# 1st Backup Folder Definition
###################################
echo "" >&1
echo "----" >&1
echo $(date +%Y-%m-%d_%H-%M-%S) " - Start rsync process - 1st Backup Folder" >&1

#Source patch - local client
SOURCE1="${HOME}/Pictures/2020/"
echo "SOURCE1 = ${SOURCE1}" >&1

#Target path on BACKUPSTORAGE
TARGET1="$3/pictures/2020/"
echo "TARGET1 = ${TARGET1}" >&1

#Exclude from RSYNC file
#EXCLUDEFILE1="${HOME}/Documents/rsync/rsync-excludefile-bilder.txt"
#echo "EXCLUDEFILE1 = ${EXCLUDEFILE1}" >&1

#BACKUP Directory
# In dieses Verzeichnis werden alle Dateien kopiert die während des rsync-Laufs durch die Option --delete gelöscht werden.
# Diese Option erzeugt eine hohe Systemlast und eine sehr lange Laufzeit des Skripts
#echo "BACKUPDIRECTORY1 = ${BACKUPDIRECTORY1}" >&1


rsync -avhbP --iconv=UTF8,UTF8-MAC --stats --delete --log-file=$1 --backup-dir=$2 ${SOURCE1} ${TARGET1}

echo "----" >&1


###################################
# 2nd Backup Folder Definition
###################################
echo "" >&1
echo "----" >&1
echo $(date +%Y-%m-%d_%H-%M-%S) " - Start rsync process - 2nd Backup Folder" >&1

#Source patch - local client
SOURCE2="${HOME}/Pictures/2021/"
echo "SOURCE2 = ${SOURCE2}" >&1

#Target path on BACKUPSTORAGE
TARGET2="$3/pictures/2021/"
echo "TARGET2 = ${TARGET2}" >&1

#Exclude from RSYNC file
#EXCLUDEFILE2=""
#echo "EXCLUDEFILE2 = ${EXCLUDEFILE2}" >&1

#BACKUP Directory
# In dieses Verzeichnis werden alle Dateien kopiert die während des rsync-Laufs durch die Option --delete gelöscht werden.
# Diese Option erzeugt eine hohe Systemlast und eine sehr lange Laufzeit des Skripts
#BACKUPDIRECTORY1="$2"
#echo "BACKUPDIRECTORY1 = ${BACKUPDIRECTORY1}" >&1


rsync -avhbP --iconv=UTF8,UTF8-MAC --stats --delete --log-file=$1 --backup-dir=$2 ${SOURCE2} ${TARGET2} 

echo "----" >&1


###################################
# 3rd Backup Folder Definition
###################################
echo "" >&1
echo "----" >&1
echo $(date +%Y-%m-%d_%H-%M-%S) " - Start rsync process - 3rd Backup Folder" >&1

#Source patch - local client = Mac
SOURCE3="${HOME}/Pictures/2022/"
echo "SOURCE3 = ${SOURCE3}" >&1

#Target path on BACKUPSTORAGE = openmediavault
TARGET3="$3/pictures/2022/"
echo "TARGET3 = ${TARGET3}" >&1

#Exclude from RSYNC file
#EXCLUDEFILE3=""
#echo "EXCLUDEFILE3 = ${EXCLUDEFILE3}" >&1

#BACKUP Directory
# In dieses Verzeichnis werden alle Dateien kopiert die während des rsync-Laufs durch die Option --delete gelöscht werden.
# Diese Option erzeugt eine hohe Systemlast und eine sehr lange Laufzeit des Skripts
#echo "BACKUPDIRECTORY3 = ${BACKUPDIRECTORY3}" >&1


rsync -avhbP --iconv=UTF8,UTF8-MAC --stats --delete --log-file=$1 --backup-dir=$2 ${SOURCE3} ${TARGET3}

echo "----" >&1

echo "${SCRIPTNAME} - Beendet"

sleep 15

exit 0



###################################
#Starts rsync Process From Source to Target
###################################
# Copies the files from Source to Target

#     -a fasst folgende Optionen zusammen:
#     -r kopiert Unterverzeichnisse
#     -l kopiert symbolische Links
#     -p behält Rechte der Quelldatei bei
#     -t behält Zeiten der Quelldatei bei,
#     -g behält Gruppenrechte der Quelldatei bei
#     -o behält Besitzrechte der Quelldatei bei (nur root)
#     -D behält Gerätedateien der Quelldatei bei (nur root)
#     -v: zeigt während des Synchronisierens alle ausgeführten Schritte an
#     -h: human readable
#     -c: aktiviert einen Dateivergleich, basierend auf Prüfsumme und nicht auf Größe und Zeitstempel. Die eigentliche Prüfsummenbildung dauert DEUTLICH länger als der Vergleich Größe und Änderungs-Zeitstempel; andererseits werden überflüssige Kopiervorgänge (z.B. bei nur geänderter Änderungszeit) vermieden.
#     -n: simuliert nur was passieren würde ("dry run")
#     -b: sorgt dafür, dass durch die Option --delete gelöschte sowie alle veränderten Objekte gesichert werden (--backup-dir=)
#     -P: aktiviert folgende Optionen:
#     --progress Fortschrittsanzeige beim Transfer anzeigen
#     --partial Fortsetzung des Transfers bei Abbruch
#     --stats: zeigt einen ausführlicheren Bericht am Ende einer Übertragung an.
#     --delete: vergleicht Quellverzeichnisse und Zielverzeichnisse und sorgt dafür, dass Dateien, die im Quellverzeichnis nicht (mehr) vorhanden sind, im Zielverzeichnis gelöscht werden. Dies kann dazu führen, dass man ungewollt Dateien löscht, die man aber noch in der Sicherung behalten möchte.
#     --ignore-existing: Überspringt die vorhandenen Daten und schreibt nur die neuen

# Sync mit einem Mac
# Umlaute produzieren Fehler bei rsync

# von Linux zu MAC
# --iconv=UTF8-MAC,UTF8

# von Mac zu Linux
#--iconv=UTF8,UTF8-MAC

# Dieser Abschnitt erklärt die Syntax von rsync
# rsync -av --stats --delete --exclude ${EXCLUDE} --exclude ${EXCLUDE1} --exclude ${EXCLUDE2} --exclude ${EXCLUDE3} --exclude ${EXCLUDE4} ${SOURCE} ${TARGET} --log-file=${LOGFILE}

# Ohne Log Files
# rsync -av --stats --exclude-from=${EXCLUDEFILE} --delete ${SOURCE} ${TARGET}

Das Automator-Skript lässt sich mit einigen Klicks auch auf dem Schreibtisch ablegen und so sehr einfach mit einem Doppelklick starten.

Die Anleitung dazu findest du in diesem Artikel ➡ https://strobelstefan.org/2022/04/08/bash-skripte-mit-automator-starten/


Gib mir gerne einen Kaffee ☕ aus!

Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕ ausgeben.

PayPal Logo


liberapay.com/strobelstefan.org


Kaffee via Bitcoin

bc1qfuz93hw2fhdvfuxf6mlxlk8zdadvnktppkzqzj


Photo by Jainath Ponnala on Unsplash

Eine Antwort auf „Backup am Mac mit Automator, Shell Skript und rsync“

  1. Moin!
    Dieses script ist ja eine Variante von deinem Artikle im April was ich seitdem, leicht abgewandelt im Betrieb habe 😉 Es fällt allerdings auf das ein „moderner“ Mac immer mehr von einem klassischem Unix System abweicht. Im Moment habe ich deshalb noch 2 Probleme mit rsync:
    1.) Seit 10.14 schreibt der bekannte Installer homebrew nicht mehr nach /usr/local/bin sondern nach /opt/homebrew (warum auch immer). Folge: es gibt 2 rsync binaries:
    /usr/bin/rsync version 2.6.9
    /opt/homebrew/bin/rsync version 3.2.6

    Das ist wichtig wenn man die scripts als LaunchAgent started (zB beim Login) wenn dann die bash environement verschieden ist!

    2.) Trotzdem läuft das Script per login-launch nicht durch. Der erste mount point wird initialisiert aber dann hängt der rsync prozess irgendwie.

    Was könnte ausser der PATH variable noch verschieden sein wenn man eine bash shell vom Terminal oder vom launchd prozess gestartet wird?

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.