Last active
August 7, 2024 13:44
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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