1

Perhaps I am missing something, but I have a bash script that takes the output of ls, makes a hash, and then takes another one. If the hashes match, no action. If they are different, it should email an admin and then overwrite the hash so they match once again. Here is the script:

logday="$(date '+%Y-%m-%d')"
sdir="/home/admin/notify"
timestamp="$(date '+%Y-%m-%dT%H:%M:%S')"
log="$sdir/log/$logday-notification.log"

if ! test -f $sdir/hash1; then touch $sdir/hash1 ls -alR /mnt/DVR/3 | md5sum > $sdir/hash1 else echo "hash already present" fi ls -alR /mnt/DVR/3 | md5sum > $sdir/hash2 if cmp -s $sdir/hash1 $sdir/hash2; then echo "$timestamp - Hash matches, nothing to do." >> "$log" else echo "$timestamp - Hash has changed! Sending notification. Writing new value to hash1" >> "$log" cp -f $sdir/hash1 $sdir/hash2 echo "it changed" | mail -s "alert" email@gmail.com fi exit

So I run the script for the first time I get the log output of:

"Hash matches, nothing to do."

Makes sense. If I cat hash*, I get this

$ cat hash*
36d28cb4a6b384abe5c3acc81c93c891  -
36d28cb4a6b384abe5c3acc81c93c891  -

Again, makes sense

If I run it again, the hashes match, no email. Again, makes sense, nothing has changed yet.

Now, I make a change to the directory. I run the script. I get: " Hash has changed! Sending notification. Writing new value to hash1"

Yup makes sense, the hashes were different. The script overwrites the hashes so they should match now. Running cat hash* confirms this.

$ cat hash*
856d69a9b53008988d034c9504345541  -
856d69a9b53008988d034c9504345541  -

Both files are identical. But now, when I run the script again, it says they are still different!

I'm starting to run out of ideas why this happens. Any ideas?

Joe
  • 19
  • 3
  • Welcome to StackExchange. That was a quite well-formed first question. – telcoM Sep 09 '23 at 04:39
  • Also: there's no point to the quotes in logday="$(date '+%Y-%m-%d')" sdir="/home/admin/notify" timestamp="$(date '+%Y-%m-%dT%H:%M:%S')" log="$sdir/log/$logday-notification.log" What you should do is quote your variables when you use them, so cp "$sdir", etc. – muru Sep 09 '23 at 04:41
  • What makes you think the problem is with cmp? – ctrl-alt-delor Sep 09 '23 at 07:59
  • Debug the cmp to eliminate it from the problem. Remove the -s, add -v (verbose), and report its status (it could be 2 for "trouble"). If a bug is not staring you in the face, it (or they) are equally likely to be anywhere, and you might as well cram in debug everywhere as you write the code. – Paul_Pedant Sep 09 '23 at 10:53
  • It might be a good idea to first send the notification email and then copy the hash, in case something goes wrong and one operation completes but the other does not. – Tanner Swett Sep 09 '23 at 12:44
  • There's an additional, subtle source of discrepancy: in the timestamp field, ls by default shows the hours and minutes of times in the last 6 months, but instead the year of older ones. That will cause a change of output exactly 6 months after a file was last modified, even though the file's timestamp hasn't actually changed. (Depending on your platform, you may be able to work around that with --full-time and/or --time-style, but… (contd.) – gidds Sep 09 '23 at 19:10
  • …there may well be other issues too. I can't help thinking that just as it's not good practice to parse ls's output, it's not good for other automated uses either.) – gidds Sep 09 '23 at 19:11
  • There's no need to touch the file before you redirect output to it. – Barmar Sep 09 '23 at 19:53

1 Answers1

6
echo "$timestamp - Hash has changed! Sending notification. Writing new value to hash1" >> "$log"
cp -f $sdir/hash1 $sdir/hash2

You say you are writing a new value to hash1, but what you actually do is copy the old hash1 value to hash2.

As a result, the two hashes will always be the same when the script is not running, but because the value is the old hash, the next run will trigger the notification again.

To fix, change the order of hashes in the cp command:

cp -f $sdir/hash2 $sdir/hash1
telcoM
  • 96,466
  • Change the cp to mv. It is a cheaper operation, and you will then spot the problem. You script tracing echos will tell you. – ctrl-alt-delor Sep 09 '23 at 08:01
  • Thanks for the help. I probably shouldn't have put this together after work when my brain wasn't working. Works like a charm now. – Joe Sep 09 '23 at 16:48
  • @Joe a contributing factor is how the names of the hash files are meaningless and generic. If you gave them names indicating their function, like new_hash and previous_hash, you would likely have noticed the cp command was backwards as you were writing it. This idea is also applicable to the names of variables you use in your scripts - meaningful names are usually better than generic ones. – Sotto Voce Sep 09 '23 at 21:01