Skip to content

Instantly share code, notes, and snippets.

@lopes
Last active August 7, 2024 13:44
Show Gist options
  • Save lopes/01d7ee4b6697e353df516c27dfd0b459 to your computer and use it in GitHub Desktop.
Save lopes/01d7ee4b6697e353df516c27dfd0b459 to your computer and use it in GitHub Desktop.
A backup script to be used with my external HDD. #shell #shellscript #backup #files #external #hdd
#!/usr/bin/env bash
#
# The MIT License (MIT)
# Copyright (c) 2016 José Lopes de Oliveira Jr.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
##
set -euo pipefail # Bash's strict mode
backup_dirs="Documents Movies Music Pictures Public"
os="$(uname -s)"
logfile="/tmp/pilsner-$(date -u +"%Y-%m-%d").log"
usage="
USAGE: pilsner.sh [OPTIONS]
OPTIONS
-h, --help Display this message and exit
-s, --sync [TARGET] Backup to [TARGET]
-c, --clean [TARGET] Delete junk files in [TARGET]
-e, --eject [DEVICE] Eject VeraCrypt container and external disk
EXAMPLES
$ pilsner.sh -s /Volumes/lopes -c /Volumes/lopes -e /dev/disk2s1
$ pilsner.sh -s /Volumes/lopes
$ pilsner.sh -c /Volumes/lopes -e /dev/disk2s1
"
sync() {
# USAGE: sync $backup_dirs
# rsync options:
# -a: archive mode
# -H: preserve hard-links
# -h: human readable numbers
# -x: don't cross file system boundaries
# -v: increase verbosity
# --numeric-ids: don't map UID/GID values
# --delete: delete extraneous files from destination directories
# --progress: show progress during transfer
# --stats: print statistics
# --exclude: files to avoid syncing
# --out-format: output format
# --log-file-format: as it says
# --log-file: one log file to rule'em all
##
while [ -n "${1:-}" ]; do
logger "info" "Syncing $1 -> $sync_target"
rsync -aHhxv --numeric-ids --delete --progress --stats \
--exclude=".DS_Store" --exclude=".fseventsd" \
--exclude=".Spotlight-V100" --exclude=".Trashes" \
--exclude=".com.apple*" --exclude="._*" \
--out-format="RSYNC: %f %b bytes" \
--log-file-format="RSYNC: %f %b bytes" --log-file="$logfile" \
"$1" \
"$sync_target"
shift
done
}
clean() {
logger "info" "Cleaning $1"
find "$1" \( -name ".DS_Store" -o -name ".fseventsd" \
-o -name ".Spotlight-V100" -o -name ".Trashes" -o -name ".com.apple*" \
-o -name "._*" \) -exec rm -rf {} \;
}
eject() {
case "$os" in
"Linux")
logger "info" "Unmounting encrypted containers"
veracrypt -d
logger "info" "Unmounting disk $1"
unmount "$1"
;;
"Darwin") # Mac
logger "info" "Unmounting encrypted containers"
/Applications/VeraCrypt.app/Contents/MacOS/VeraCrypt -d
logger "info" "Unmounting disk $1"
diskutil unmount "$1" #/dev/disk2s1
;;
*)
logger "error" "Unsuportted operating system: $os"
exit 1
;;
esac
}
logger() {
# USAGE: logger LEVEL MESSAGE
iso8601utc="$(date -u +"%Y%m%dT%H%M%SZ")"
case "$1" in
"info") log="$iso8601utc INFO: $2" ;;
"warning") log="$iso8601utc WARNING: $2" ;;
*)
log="$iso8601utc ERROR: Unrecognized log level: $1"
exit 1
;;
esac
echo "$log" |tee -a "$logfile"
}
##
# MAIN
# Processing args.
while [ -n "${1:-}" ]; do
case "${1:-}" in
-s | --sync) shift; sync_target="$1" ;;
-c | --clean) shift; clean_target="$1" ;;
-e | --eject) shift; eject_target="$1" ;;
-h | --help) echo "$usage"; exit 0 ;;
*) echo "$usage"; exit 1 ;;
esac
shift
done
cd ~
if [ -n "${sync_target:-}" ]; then
# TODO: test if $sync_target exists and is writable
sync $backup_dirs # do not use double quotes here!
fi
if [ -n "${clean_target:-}" ]; then
# TODO: test if $clean_target exists and is writable
clean "$clean_target"
fi
if [ -n "${eject_target:-}" ]; then
# TODO: test if $eject_target exists and is unmountable
eject "$eject_target"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment