#!/bin/sh NORM="\033[0m" CYN="\033[0;36m" GRN="\033[0;32m" RED="\033[0;31m" me="$(basename "$0")" concat="pv -EE -F'%r [%b] [%t] [%e] %p'" printhelp() { cat << HELPDOC Usage: $me [options] [file/directory]... OPTIONS: -o, --stdout Output checksum to STDOUT -S, --supress Supress all warnings and progress notes (default with -o) -n, --no-progress Don't output progress bar (default with -o & -S) -m, --md5 Create/verify md5 checksum -s[mode], --sha[mode] Create/verify sha[mode] checksum -x[mode], --xxh[mode] Create/verify xxh[mode] checksum (default) -c [alg], --crypt [alg] Create/verify [alg] checksum (uses [alg]sum program; e.g. '-c sha256' uses sha256sum) -v, --verify Verify files with existing checksums -h, --help Print help HELPDOC } crypt=xxh while true; do case "$1" in -o|--stdout) stdout=1; nowarn=1; concat="cat" ;; -S|--supress) nowarn=1; concat="cat" ;; -n|--no-progressbar) concat="cat" ;; -m|--md5) crypt=md5 ;; -s*|--sha*) crypt=sha$(echo "$1" | tr -cd [:digit:]) ;; -x*|--xxh*) crypt=xxh$(echo "$1" | tr -cd [:digit:]) ;; -c|--crypt) crypt=$2 && shift ;; # Shift twice -v|--verify) verify=1 ;; -h|--help) printhelp; exit 0 ;; -*) printhelp; exit 2 ;; *) break ;; esac shift done hashalg=${crypt}sum command -v $hashalg >/dev/null || (echo "Hashing algorithm '$hashalg' does not exist!" && exit 2) # Warn user if [ ! "$nowarn" ]; then for file in "$@"; do [ -d "$file" ] && echo "${RED}NOTE:${NORM} getting a checksum from an entire directory is NOT a standard feature in any other checksum-checking program! They can only be checked with this script!" && break done fi while [ -n "$1" ]; do file="$1" [ ! "`echo "$file" | sed "s/.$crypt$//"`" = "$file" ] && shift && continue # Skip hash files [ ! -e "$file" ] && echo "file '$file' does not exist!" && exit 1 [ -d "$file" ] && type=directory || type=file hashfile="$file.$crypt" [ -n "$verify" ] && [ ! -e "$hashfile" ] && shift && continue # Skip files without a hash in verify mode [ ! "$nowarn" ] && echo "Getting $crypt checksum of $type '$file'..." hash=`find "$file" -type f -print0 | sort -z | xargs -r0 $concat | $hashalg | cut -d' ' -f1` if [ "$stdout" ]; then echo "$hash ($crypt) $file" else if [ -e "$hashfile" ]; then phash=`cat "$hashfile"` [ $phash = $hash ] \ && echo "${GRN}Success: $type matches saved checksum!" \ || (echo "${RED}Error: $type does not match saved checksum!\nExpected checksum: $phash\nActual checksum: $hash" && ec=1) else echo $hash > "$hashfile" \ && echo "${CYN}$crypt checksum file saved at '$hashfile'!" \ || (echo "${RED}'$hashfile' could not be created!\n$crypt checksum of $type '$file' is $hash" && ec=1) fi printf "$NORM"; [ -n "$2" ] && echo fi shift done exit $ec