4
\$\begingroup\$

You know how whenever you download a file you should really compare the hash of the download to the one provided on the website? This makes absolute sense, but it's a pain to do it letter for letter, digit for digit. So, I wrote this little script to take care of the job. Any comments are welcome.

#!/bin/bash

# hash_checker - program to verify a downloaded file

error_exit()
{
    echo "$1" 1>&2
    exit 1
}

usage="usage: hash_checker downloaded_file hash_provided -a algorithm"
downloaded_file=
hash_given=
hash_calc=
algo="sha256"

# check if file and hash were provided
if [ $# -lt 2 ]; then
    error_exit "$usage"
fi

# parsing the provided hash and file
downloaded_file="$1"
hash_given="$2"

# parsing the algorithm, if provided
if [ "$3" != "" ]; then
    if [ "$3" = "-a" ]; then
        algo="$4"
    else
        error_exit "$usage"
    fi
fi

# check if input is a valid file
if [ ! -f "$downloaded_file" ]; then
    error_exit "Invalid file! Aborting."
fi

# calculate the hash for the file
hash_calc="$($algo'sum' $downloaded_file)"
hash_array=($hash_calc)
hash_calc=${hash_array[0]}

# compare the calculated hash to the provided one
if [ "$hash_calc" = "$hash_given" ]; then
    echo "The hashes match. File seems to be valid."
else
    echo "The hashes do not match. File does not seem to be valid."
fi
\$\endgroup\$
  • \$\begingroup\$ Why not just use the -c option to sha1sum or md5sum to do the comparison? \$\endgroup\$ – Toby Speight Sep 13 '18 at 7:16
  • \$\begingroup\$ Didn't know that was an option. Kinda expected something like this must exist, thanks. \$\endgroup\$ – iuvbio Sep 13 '18 at 7:25
3
\$\begingroup\$

Notes:

  • I'd use getopts for arg parsing -- lots of examples on stackoverflow about how to use it.
  • always quote your variables
  • you should validate the algorithm:

    sum_exe="${algo}sum"
    if ! type -P "$sum_exe" >/dev/null; then
        error_exit "'$algo' is an unknown checksum algorithm"
    fi
    
  • have the checksum program read from stdin, then you don't have to do your incorrect unsafe word parsing since the program will not print a filename

    hash_calc=$( "$sum_exe" < "$downloaded_file" )
    

    As the above doesn't work, let's use read from a process substitution

    read -r hash_calc _ < <("$sum_exe" < "$downloaded_file")
    
\$\endgroup\$
  • \$\begingroup\$ Thanks for your notes. Reading from stdin the filename is not printed, but ` -` is appended to the hash, and thus the test fails. Is there a way around that other than more word parsing? \$\endgroup\$ – iuvbio Sep 12 '18 at 20:21
  • \$\begingroup\$ I've updated my answer \$\endgroup\$ – glenn jackman Sep 12 '18 at 20:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.