Skip to content

Instantly share code, notes, and snippets.

@DavesCodeMusings
Last active June 3, 2023 18:24
Show Gist options
  • Select an option

  • Save DavesCodeMusings/8b1e4f5fba963a8b6c105e32397a409d to your computer and use it in GitHub Desktop.

Select an option

Save DavesCodeMusings/8b1e4f5fba963a8b6c105e32397a409d to your computer and use it in GitHub Desktop.
Not too bad backup to external disk
This shell script will back up files from remote systems as well as local
using rsync. Default behavior is to prune any backups older than 90 days,
except for Sundays. This results in daily copies for up to 90 days and weekly
copies for anything older.
Sample crontab entries to back up multiple hosts on a schedule:
0 6 * * * /media/backup/backup.sh lorum.home
0 7 * * * /media/backup/backup.sh ipsum.home
0 8 * * * /media/backup/backup.sh dolor.home
The script takes a single command-line argument of the host's name. (Backing
up the host where the script is running requires the hostname as well for
directory naming purposes.)
To backup remote hosts, you'll need to configure ssh keys first, so rsync
can log in without a password.
Date calculations are done so they are compatible with the date command
supplied by busybox (used in Alpine Linux) rather than relying on added
functionality in GNU date.
I am sharing this script for educational purposes only. Please, for the love
of Pete, don't use it to back up anything important. This script comes with
NO WARRANTY, not even the implied warranty of fitness for particular purpose.
#!/bin/sh
BASE_DIR=/media/backup
[email protected] # Comment out to disable email summary.
PRUNE_DAYS=90 # Set to 0 to disable pruning, otherwise days of retention.
if [ "$1" == "" ]; then
echo "Usage:"
echo " $0 server-name"
exit 1
fi
# Save space with hardlinks to files that are unchanged from yesterday.
YESTERDAY=$(/bin/date -d @$(($(/bin/date +%s) - 86400)) +%Y/%m/%d)
YESTERDAY_DIR=${BASE_DIR}/${1}/${YESTERDAY}
HARDLINK_OPTION="--link-dest=${YESTERDAY_DIR}"
[ -d ${YESTERDAY_DIR} ] || unset HARDLINK_OPTION
# Destination for today's backup.
TODAY_DIR=${BASE_DIR}/${1}/$(date '+%Y/%m/%d')
mkdir -p ${TODAY_DIR} || exit 2
cd ${TODAY_DIR} || exit 2
# Local and remote backups have slight differences.
LOG_FILE=${BASE_DIR}/${1}.log
if [ "${1}" == "$(uname -n)" ]; then
rsync -av ${HARDLINK_OPTION} \
--exclude-from=${BASE_DIR}/exclude.txt \
--stats \
/ . >${LOG_FILE} 2>&1
else
ping -c1 ${1} >${BASE_DIR}/${1}.log 2>&1 || exit 4
rsync -avz ${HARDLINK_OPTION} \
--exclude-from=${BASE_DIR}/exclude.txt \
--stats \
root@${1}:/ . >>${LOG_FILE} 2>&1
fi
# Optionally remove older backup directories to save space, but keep Sundays.
if [ ${PRUNE_DAYS} -ne 0 ]; then
NOW=$(/bin/date +%s) # current datetime in seconds.
PRUNE_AGE=$((${PRUNE_DAYS} * 86400)) # Expressed in seconds.
PRUNE_DAY=$(/bin/date -d @$((${NOW} - ${PRUNE_AGE})) +%u)
PRUNE_DATE=$(/bin/date -d @$((${NOW} - ${PRUNE_AGE})) +%Y/%m/%d)
PRUNE_DIR=${BASE_DIR}/${1}/${PRUNE_DATE}
echo "" >>${LOG_FILE}
if [ ${PRUNE_DAY} -eq 7 ]; then # Sunday=7, Monday=1, Tuesday=2, etc.
echo "Retaining weekly backup: ${PRUNE_DIR}" >>${LOG_FILE}
else
echo "Pruning ${PRUNE_DAYS} day old backup: ${PRUNE_DIR}" >>${LOG_FILE}
[ -d ${PRUNE_DIR} ] && rm -Rf ${PRUNE_DIR}
fi
fi
# Report space left on backup device in a friendly way.
df -h ${BASE_DIR} | awk 'NR>1 { printf "\n%s: %s of %s (%s) used.\n", $1, $3, $2, $5 }' >>${LOG_FILE}
# Email a summary.
if [ "${MAIL_TO}" != "" ]; then
tail -16 ${BASE_DIR}/${1}.log | mail -s "${1} backup" ${MAIL_TO}
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment