1

I am using sha256sum to check whether file has changed or not within the bash script. My idea is to first store the sha256sum in a *.sha256 file. Then if this is present then use this for sha256 comparison using --check command. If hashes match then continue the rest of script otherwise create new hash file (*.sha256) and replace the older one with new hash file. I have done:

x="/home/test.json"

if [[ -s $x.sha256 ]]; then
        sha256sum --check $x.sha256
        #exit 1
        s1=$(sha256sum "$x" > "$x.sha256")
        #exit 1
else
        s1=$(sha256sum "$x" > "$x.sha256")
        echo "sha256 file is created"
fi

But from above code initially if x.sha256 file is not present, then it is created. But if file is already available and hashes doesn't match then it throws error:

/home/test.json: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match

This is expected but in this case I want to create new x.sha256 file and replace old file.

Can anyone please let me know what changes is needed?

Thanks in advance

8
  • Sounds a bit like Tripwire? Aug 9, 2022 at 11:57
  • s1=$(sha256sum "$x" > "$x.sha256") should be sha256sum "$x" > "$x.sha256" Aug 9, 2022 at 11:59
  • Hello @roaima, I made the above change. But, this didn't help. I still have same behavior.
    – Preeti
    Aug 9, 2022 at 12:26
  • TBH I'm not entirely clear what you think the problem is Aug 9, 2022 at 12:41
  • You're running sha256sum on "$x" regardless of if the check fails so it looks like it should update the .sha256 file after giving the warning. The command substitution in s1=$(sha256sum "$x" > "$x.sha256") is a bit useless, though, as you're redirecting the output of sha256sum to a file, there's no output for the shell to catch. It shouldn't affect what the program does, however. Also, it doesn't look like you're using s1. If you are, and want to get the output of sha256sum to a file and to a shell variable, then use something like s1=$(sha256sum "$x" | tee "$x.sha256")
    – ilkkachu
    Aug 9, 2022 at 12:48

1 Answer 1

2

From the comment:

But the script uses set -Eeo pipefail

set -e causes the whole script to fail if and when sha256sum --check exits with a falsy status. To avoid that, put the command in any sort of conditional, e.g. run sha256sum --check || true instead.

Also, as mentioned, s1=$(sha256sum "$x" > "$x.sha256") looks a bit off, as the output from sha256sum is redirected to a file, there's nothing for the command substitution to catch, and $s1 ends up empty regardless of what happens. If you don't need s1, just drop the command substitution, and if you want to put the output of sha256sum in both the variable and the file, use something like

s1=$(sha256sum "$x" | tee "$x.sha256")

So, I'd rewrite the whole script as something like this:

#!/bin/bash

set -e
file="/home/test.json"

if [[ -s $file.sha256 ]]; then
    if ! sha256sum --check "$file.sha256"; then
        echo "stored hash for '$file' does not match existing file, storing new hash"
        sha256sum "$file" > "$file.sha256"
    else
        : # hash file exists and matches existing file, do nothing
    fi
else
    echo "no stored hash for '$file', creating hash file"
    sha256sum "$file" > "$file.sha256"
fi

That is, unless you need a copy of the hash further in the file, in which case the branch for an existing matching hash also needs to read "$file.sha256" in.

But if you're using set -e, see BashFAQ/105 -- Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .