Um mit meiner Linuxdistribution eine Datensicherung auf eine Timecapsule von Apple zu schreiben suchte ich ein Werkzeug, fand es nicht und programmierte es schlussendlich selbst. ­čÖé

Features

  • Volle oder inkrementelle Datensicherung
  • Optional: Notification mit Info
  • Versteckte Ordner oder Dateien ausschlie├čen
  • Nach x Minuten wiederholen
  • Rasend schnell:
    Ver├Ąnderte Dateien werden zuerst lokal ermittelt und dann erst per rsync transferiert

Code

#!/bin/bash
#v1.0
:<<hBackup
	INSTALLATION
	1. If notification or progress should be shown, install yad
	2. Copy this file to your folder bin:
	
		debian:	/usr/local/bin	(for current user)
				/usr/bin		(for all users)
hBackup
# reserved names: start, stop, true
# constants
LOC="$HOME/.hBackup"
ITEMS="$LOC/.ITEMS"
COUNTER="$LOC/.COUNTER"
IFS='
'
Help(){
	cat <<HELP
Usage: hBackup SOURCE... DEST... [-OPTIONS] [x]

  f  Full backup (otherwise only modified files since last backup)
  h  Exclude hidden folders in source directory
  H  Exclude all hidden files and folders
  n  Show notification
  x  Repeat sync after x minutes

Example: hBackup /home/user/source /media/backupServer -fHpn 30
HELP
	exit
}
Args(){
	# at least 2 arguments
	if ! [ "$2" ]; then
		echo 'ERROR: I need at least 2 arguments: Source and Destination'
		Help
	fi
	# SOURCE
		if ! [ -d "$1" ]; then
			echo "ERROR: '$1' is not a direcory"
			Help
		fi
		SOURCE="$1"
	# DEST
		if ! [ -d "$2" ] ; then
			echo "ERROR: '$2' is not a direcory"
			Help
		fi
		DEST="$2"
	# OPTIONS
		if [[ "$3" =~ 'f' ]]; then
			TYPE='full'
		else
			TYPE='incremental'
		fi
		if [[ "$3" =~ 'n' ]]; then
			NOTIFICATION=true
		fi
		if [ "$4" ]; then
			if [ "$4" -gt 0 ]; then
				REPEAT="$4"
			else
				echo "ERROR: '$4' is not a number"
				Help
			fi
		else
			REPEAT=0
		fi
		FIND="find . -type f ! -path '$LOC/*'"
			if [[ "$3" =~ 'h' ]]; then
				EXCLUDE='hidden folders in source directory'
				FIND="$FIND ! -path '\./\.*'"
			elif [[ "$3" =~ 'H' ]]; then
				EXCLUDE='everything hidden'
				FIND="$FIND ! -path '*/\.*'"
			else
				EXCLUDE='nothing'
			fi
		echo $FIND
}
Notify(){
	# <tooltip>/stop [start/pause]
	# @ tooltip
	if [ "$NOTIFICATION" ] && [ "$2" == 'start' ]; then
		if [ "$NOTIFICATION" == true ]; then
			exec 3> >(yad --notification --kill-parent=20 --listen)
			NOTIFICATION=start
		fi
		echo "icon:btsync-gui-connecting" >&3
		echo "menu:Quit hBackup!kill -$$" >&3
	elif [ "$NOTIFICATION" ] && [ "$2" == 'pause' ]; then
		echo "icon:btsync-gui-disconnected" >&3
	elif [ "$NOTIFICATION" ] && [ "$1" == 'stop' ]; then
		exec 3>&- # stop
		NOTIFICATION=
	fi
	if [ "$NOTIFICATION" ]; then
		echo "tooltip:$1" >&3
	fi
}
Sync(){
	path=${SOURCE//\//-}
	path=${path#-}
	lastB="$DEST/.$path.lastB"
	cd "$SOURCE"
	id="$path-$(date +%Y%m%d%H%M%S)"
	fid="$id"
	# <info> [logFile]
	# @ timeStamp info
	Logit(){
		info=$(date '+%Y-%m-%d %H:%M:%S')
		if [ "$2" ]; then
			echo "$info $1" >> "$2"
		else
			echo "$info $1" >> "$LOC/.$fid.log"
		fi
		echo "$info $1"
	}
	# new or old backup
		if [ -f "$COUNTER" ] && [ -f "$ITEMS" ]; then
			resumedBackup=true
			Logit 'Resume Backup'
			Notify 'Resume Backup' 'start'
			counter=$(cat "$COUNTER")
		else
			if [ "$TYPE" == 'incremental' ] && [ -f "$lastB" ]; then
				NFIND="$FIND -newer '$lastB'"
				fid="$id"
			else
				NFIND="$FIND"
				fid="$id"_full
			fi
			resumedBackup=''
			Logit 'New Backup'
			Notify 'New Backup' 'start'
			Logit "TYPE=$TYPE"
			Logit "LASTB=$(cat "$lastB" 2> /dev/null)"
			Logit "EXCLUDE=$EXCLUDE"
			Logit "REPEAT=$REPEAT min"
			eval $NFIND | sed -e 's/\.\///' > "$ITEMS"
			date '+%Y-%m-%d %H:%M:%S' > "$lastB"
			echo $((counter=1)) > "$COUNTER"
		fi
	# count items
		sumItems=$(cat $ITEMS | wc -l)
		items=$((sumItems-counter+1))
		Logit "$items/$sumItems files, $counter. line"
	# copy items
		for item in $(tail -n "+$counter" "$ITEMS"); do
			proz=$((100/sumItems*counter))
			Logit "$item"
			Notify "[$proz%] $item"
			rsync -R "$item" "$DEST/$fid/"
			echo $((++counter)) > "$COUNTER"
		done
		rm "$ITEMS" "$COUNTER"
	# mv logfile
		cd "$LOC"
		for logFile in $(find . -name '.*.log' | sed -e 's/\.\/\.//')
		do
			dir=${logFile%.log}
			Logit "[L] .$logFile" ".$logFile"
			Notify "[L] .$logFile"
			rsync --remove-source-files ".$logFile" "$DEST/$dir/"
		done
	# repeat
		if [ "$resumedBackup" ]; then
			Sync
		elif [ "$REPEAT" -gt 0 ]; then
			i=$REPEAT
			while [ $i -gt 0 ]; do
				Notify "Next backup in $i minute(s)" 'pause'
				echo "Next backup in $i minute(s)"
				((i--))
				sleep 60
			done
			Sync
		fi
}
Args "$@"
Notify 'hBackup' start
Sync
Notify stop