Skip to content

Instantly share code, notes, and snippets.

@lulichn
Last active March 30, 2018 00:59
Show Gist options
  • Save lulichn/99513d2b03aee0922e9be3004bb18790 to your computer and use it in GitHub Desktop.
Save lulichn/99513d2b03aee0922e9be3004bb18790 to your computer and use it in GitHub Desktop.
rsync TimeMachine
#!/bin/bash
#
# Backup mimicking Time Machine from Mac OS X using rsync
# --- Variables --- #
OS=$(uname -s)
HOST=$(hostname)
DATE_FORMAT=$(date "+%Y-%m-%d-%H%M%S")
CURRENT_YEAR=$(date +%Y)
CURRENT_MONTH=$(date +%m)
#RSYNC_OPTIONS="--recursive --links --times -D -O --partial --progress --human-readable"
RSYNC_OPTIONS="-auE --partial --progress --human-readable"
# Use absolute paths. Relative paths tend to break the hard linking advantage of rsync.
# Paths can include spaces as long as variable contents are double quoted
# SOURCE="[absolute path to source directory]"
# DESTINATION="[absolute path to backup destination]/$HOST"
# http://qiita.com/usagimaru/items/134a4ed0642e1f9ae1e7
SOURCE="${1%/}"
DESTINATION="${2%/}/$HOST"
EXCLUDEDFILES="${3%/}"
# --- Main Program --- #
# Create destination if it does not exist
if [[ ! -d "$DESTINATION" ]] ; then
mkdir -p "$DESTINATION"
fi
# Make inital backup if Latest does not exist, otherwise only copy what has changed
# and hard link to files that are the same
if [[ ! -L "$DESTINATION"/Latest ]] ; then
rsync $RSYNC_OPTIONS \
--delete \
--exclude-from=$EXCLUDEDFILES \
"$SOURCE" "$DESTINATION"/$DATE_FORMAT
else
rsync $RSYNC_OPTIONS \
--delete \
--delete-excluded \
--exclude-from=$EXCLUDEDFILES \
--link-dest="$DESTINATION"/Latest \
"$SOURCE" "$DESTINATION"/$DATE_FORMAT
fi
# Remove symlink to previous Latest backup
rm -f "$DESTINATION"/Latest
# Create symlink to latest backup
ln -s $DATE_FORMAT "$DESTINATION"/Latest
# --- Remove old backups --- #
# BSD date in OS X has a different syntax than GNU date in Linux
if [[ $OS == "Darwin" || $OS == "FreeBSD" ]]; then
# Return YYYY one year ago from today
LAST_YEAR=$(date -v -1y "+%Y")
elif [[ $OS == "Linux" ]]; then
# Return YYYY one year ago from today
LAST_YEAR=$(date -d "last year" "+%Y")
fi
# Keep monthly backups for one year
for (( month = 1 ; month < $CURRENT_MONTH ; month++ )); do
# List latest backup from each month of current year
# Use printf to pad the single digit months with a 0
LATEST_BACKUP=$(find "$DESTINATION" -mindepth 1 -maxdepth 1 -name ${CURRENT_YEAR}-$(printf "%02d" $month)-* | sort | tail -n 1)
find "$DESTINATION" -mindepth 1 -maxdepth 1 -name ${CURRENT_YEAR}-$(printf "%02d" $month)-* | grep -v "$LATEST_BACKUP" | xargs -I {} rm -rf {}
done
for (( month = $CURRENT_MONTH ; month <= 12 ; month++ )); do
# List latest backup from each month of current year
# Use printf to pad the single digit months with a 0
LATEST_BACKUP=$(find "$DESTINATION" -mindepth 1 -maxdepth 1 -name ${LAST_YEAR}-$(printf "%02d" $month)-* | sort | tail -n 1)
find "$DESTINATION" -mindepth 1 -maxdepth 1 -name ${LAST_YEAR}-$(printf "%02d" $month)-* | grep -v "$LATEST_BACKUP" | xargs -I {} rm -rf {}
done
# Remove backups older than one year
for (( month = 1 ; month < $CURRENT_MONTH ; month++ )); do
find "$DESTINATION" -mindepth 1 -maxdepth 1 -type d -name "$LAST_YEAR-$(printf "%02d" $month)-*" | xargs -I {} rm -rf {}
done
find "$DESTINATION" -mindepth 1 -maxdepth 1 -type d ! -name "$CURRENT_YEAR-*" | grep -v "$LAST_YEAR-*" | xargs -I {} rm -rf {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment