Skip to content

Instantly share code, notes, and snippets.

@gandalfx
Last active August 29, 2015 14:01
Show Gist options
  • Save gandalfx/9235ddc636511015a087 to your computer and use it in GitHub Desktop.
Save gandalfx/9235ddc636511015a087 to your computer and use it in GitHub Desktop.
Minecraft Saves Backup Manager (can be used for other stuff as well)
#!/bin/bash
set -e
help_text='
McBackup creates and manages backups of your Minecraft game saves.
Game saves are expected to be stored in ~/.minecraft/saves.
Backups are stored in ~/.minecraft/backups by default.
To change this edit the $mcdir and $backupdir variables.
McBackup will manage multiple copies of varying age of each game save.
Old backups will be discarded incrementally.
Usage:
/path/to/mcbackup.sh [OPTIONS] [SAVES]
OPTIONS See below
SAVES Can be a list of names of game saves to be backed up.
May be omitted if the -a option is used (see below).
The name of the directory inside $mcdir/saves/ is relevant.
Note that this may not be identical to the name displayed in-game.
Saves that do not have a corresponding directory inside the
$backupdir/ will be skipped unless the -f switch is specified.
Options:
-a Backup all saves that are inside $mcdir/saves/.
If used with -d, process all backups inside $backupdir/
(regardless of whether they exist inside $mcdir/saves/)
-d Discard only. Do not create new backups but check existing ones for
obsolete versions
-f Force backup creation. If a save does not have a corresponding
directory inside $backupdir/ that directory will be created.
-h Show this help text and exit.
-n No discarding. Only create backups, do not check if any are outdated.
Created by Gandalfx
https://gandalfx.github.com
'
################
### settings ###
################
mcdir="$HOME/.minecraft"
backupdir="$HOME/.minecraft/backups"
#################
### functions ###
#################
# creates a new backup if possible and necessary
# param 1 is save's (base)name
function update_backup {
local save="$(basename "$1")"
if [[ ! -d "$mcdir/saves/$save" ]] ; then
echo "skipping '$save'..."
return
fi
echo -en "checking $bold$blue$save$end: "
if [[ ! -d "$backupdir/$save" ]] ; then
if $flag_force ; then
echo -e "${green}creating backup at '$backupdir/$save'..."
mkdir -p "$backupdir/$save"
else
echo -e "$red'$backupdir/$save' doesn't exist!$end skipping..."
return
fi
fi
if [ ! -e "$backupdir/$save/latest" ] ||
[[ $(diff -rq "$mcdir/saves/$save" "$backupdir/$save/latest") != "" ]]
then
echo -e "${red}backup outdated!$end"
local today=$(date +%F)
echo "syncing files..."
rsync -a --delete "$mcdir/saves/$save/" "$backupdir/$save/$today"
ln -snf "$backupdir/$save/$today" "$backupdir/$save/latest"
$flag_no_discard || discard_old_backups "$backupdir/$save"
else
echo -e "${green}up to date$end"
fi
}
# manages old saves
# param 1 is path containing saves
function discard_old_backups {
pushd . > /dev/null
cd "$1"
local saves=(*-*-*) # format is yyyy-mm-dd
unset saves[${#saves[@]}-1] # always keep youngest save
unset days week month year # steps
for save in "${saves[@]}" ; do
# echo "found save $save"
if [[ $save < $(date +%F -d "1 year ago") ]] ; then
# $save is older then a year
# -> keep youngest
if [[ $year ]] ; then
rm -r $year
echo "removed old save '$PWD/$year'"
fi
local year=$save
elif [[ $save < $(date +%F -d "1 month ago") ]] ; then
# $save is older then a month but younger then a year
# -> keep oldest
if [[ $month ]] ; then
rm -r $save
echo "removed old save '$PWD/$save'"
else
local month=$save
fi
elif [[ $save < $(date +%F -d "1 week ago") ]] ; then
# $save is older then a week but younger then a month
# -> keep oldest
if [[ $week ]] ; then
rm -r $save
echo "removed old save '$PWD/$save'"
else
local week=$save
fi
elif [[ $save < $(date +%F -d "2 days ago") ]] ; then
# $save is older then 2 days but younger then a week
# -> keep oldest
if [[ $days ]] ; then
rm -r $save
echo "removed old save '$PWD/$save'"
else
local days=$save
fi
fi
done
popd > /dev/null
}
###########
### run ###
###########
# use colors only for terminal output
if [[ -t 1 ]] ; then
red="\e[91m"
blue="\e[34m"
green="\e[32m"
bold="\e[1m"
end="\e[0m"
fi
# parse flags
flag_all=false
flag_force=false
flag_no_discard=false
flag_discard_only=false
while getopts "afndh" opt ; do
case "$opt" in
a) flag_all=true;;
f) flag_force=true;;
n) flag_no_discard=true;;
d) flag_discard_only=true;;
h) printf "$help_text"; exit;;
*) exit 1;;
esac
done
# remove flags from parameter list
shift $(($OPTIND - 1))
if $flag_discard_only ; then
$flag_all && saves=( "$backupdir/"* ) || saves=( $@ )
[[ $saves ]] || echo "no saves specified!"
for save in "${saves[@]}" ; do
save="$(basename "$save")"
if [[ -d "$backupdir/$save" ]] ; then
discard_old_backups "$backupdir/$save"
else
echo "'$save' has no backups."
fi
done
else
$flag_all && saves=( "$mcdir/saves/"* ) || saves=( $@ )
[[ $saves ]] || echo "no saves specified!"
for save in "${saves[@]}" ; do
update_backup "$save"
done
fi
### an old friend
# for age in saves_2*; do for sav in $age/* ; do mkdir -pv "backups/$(basename "$sav")" && cp -ru "$sav" "backups/$(basename "$sav")/${age#saves_}"; done; done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment