Skip to content

Instantly share code, notes, and snippets.

@lhns
Last active May 15, 2018 10:32
Show Gist options
  • Save lhns/f13c07e4350c2408f5af7f00c2800a82 to your computer and use it in GitHub Desktop.
Save lhns/f13c07e4350c2408f5af7f00c2800a82 to your computer and use it in GitHub Desktop.
#!/bin/bash
# path to tar file
# 1 input: path
# stdout: tar file
pathToTar() {
path="$1"
if [[ "$path" == /* ]]
then
tar -cf - --ignore-failed-read -C / "${path:1}"
else
tar -cf - --ignore-failed-read "$path"
fi
}
# tar file to path
# 1 output: path
# stdin: tar file
tarToPath() {
tar -C "$1" -xf -
}
# convert file to hex file
# stdin: file
# stdout: hex file
toHex() {
xxd -ps -c 8
}
# convert hex file to file
# stdin: hex file
# stdout: file
fromHex() {
xxd -r -ps
}
# file1 -> bin diff -> file2
# 1 input: file1
# 2 input: file2
# stdout: bin diff
binDiff() {
diff <(cat "$1" | toHex) <(cat "$2" | toHex) | compress
}
# file1 -> bin diff -> file2
# stdin: bin diff
# 1 input: file1
# stdout: file2
applyBinDiff() {
tmpfile="$(mktemp)"
cat "$1" | toHex > "$tmpfile"
decompress | patch -N -o - "$tmpfile" 2>/dev/null | fromHex
rm "$tmpfile"
}
# file to compressed file
# stdin: file
# stdout: compressed file
compress() {
gzip
}
# compressed file to file
# stdin: compressed file
# stdout: file
decompress() {
gunzip
}
# 1 input: backup path
# stdout: full backup archive
pathToFullBackup() {
pathToTar "$1" | tee >(wc -c >&2) | compress | tee >(wc -c >&2)
}
# stdin: full backup archive
# 1 input: backup path
# stdout: diff backup archive
pathToDiffBackup() {
decompress | binDiff - <(pathToTar "$1" | tee >(wc -c >&2)) | tee >(wc -c >&2)
}
# stdin: diff backup archive
# 1 input: full backup archive
# stdout: full backup tar
diffToFullBackupTar() {
applyBinDiff <(cat "$1" | decompress)
}
# Usage:
# backup [path] [archive]: create full backup
# backup -d [full backup] [path] [archive]: create differential backup
# backup -r [path] [archive]: restore full backup
# backup -r -d [full backup] [path] [archive]: restore differential backup
# Cron example:
# 0 1 1 * * backup "/etc" "/var/backup-full-$(date '+%Y%m%d%H%M%S')"
# 0 4 * * * backup -d "/var/$(ls -1 "/var" | grep "backup-full-" | sort -rn | head -1)" "/etc" "/var/backup-$(date '+%Y%m%d%H%M%S')"
if [[ "$1" == "-r" ]]; then
# restore
shift
if [[ "$1" == "-d" ]]; then
# differential
fullBackupPath="$2"
shift 2
cat "$2" | diffToFullBackupTar "$fullBackupPath" | tarToPath "$1"
else
# full
cat "$2" | decompress | tarToPath "$1"
fi
else
# create
log=$((
if [[ "$1" == "-d" ]]; then
# differential
fullBackupPath="$2"
shift 2
cat "$fullBackupPath" | pathToDiffBackup "$1" > "$2"
else
# full
pathToFullBackup "$1" > "$2"
fi
) 3>&2 2>&1 1>&3) 2>&1
sizePre=$(echo "$log" | cut -d $'\n' -f 1)
sizePost=$(echo "$log" | cut -d $'\n' -f 2)
echo "Size before compression: $sizePre"
echo "Size after compression: $sizePost"
echo "Compression ratio: $(( $sizePre / $sizePost ))"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment