To configure script to send email only when diff command gives a difference
The problem is the command you're using to do the diff
. Every time that command runs the results of it, whether there's a difference or not, will trigger the mail
command.
Example
Here we're going to simulate the 2 files using 2 echo
commands like so:
$ diff <(echo 1) <(echo 2)
1c1
< 1
---
> 2
That seems OK, but what happens when the echo
commands are the same thing?
$ diff <(echo 1) <(echo 1)
$
OK, so that doesn't seem to be an issue, or is it? What if we pipe the output from the diff
command to say another echo
command:
$ diff <(echo 1) <(echo 1) | echo "hi"
hi
See even empty output from diff
piped to another command will trigger that command to run.
So then what's the right way?
What you really want to do is one of 2 things. Either check the status of the diff
command, or use a logical operator such and &&
(and) or the operator ||
(or operator).
Status
Most commands when executed return a status. Usually a zero or a one to denote that they ran successfully or failed. You can see the status from diff
by analyzing the status variable $?
in Bash.
diff
returns a 0 if the files match
$ diff <(echo 1) <(echo 1)
$ echo $?
0
diff
returns a 1 if the files don't match
$ diff <(echo 1) <(echo 2)
1c1
< 1
---
> 2
$ echo $?
1
So by itself it seems useful, we can tell whether a command ran successfully or not. However we don't have a way to act on this. So let's look at the logical operators.
Logical operator
The other method is to change 2 commands so that if the first one is successful, then the second one will run. Conversely you can use the alternative operator to run a second command, if the first failed.
Example
different pragma
$ diff <(echo 1) <(echo 2) || echo "they're different"
1c1
< 1
---
> 2
they're different
same pragma
$ diff <(echo 1) <(echo 1) && echo "they're the same"
they're the same
NOTE: Some caution should be used if you use this method. There is one issue with type of structure, because the above are true logical operators in the same way that a if .. then .. else is. You can read about these on the bashpitfalls website.
So this seems like a valid approach. But maybe there's another way. Keep reading.
If then else
A third method would be to enlist a if/then block to run the mail
program. if/then commands are related to the logical operators I mentioned a minute ago, they're called conditionals.
NOTE: Also diff
really isn't the best tool for use in if/then statements. It's better to use the cmp
command which can return just a status and nothing more. So let's upgrade that now too.
Example
same
$ cmp -s <(echo 1) <(echo 1)
$ echo $?
0
different
$ cmp -s <(echo 2) <(echo 1)
$ echo $?
1
Extending this into an if/then block would look something like this:
$ if cmp -s <(echo 2) <(echo 1);then echo "same"; else echo "different";fi
different
$ if cmp -s <(echo 1) <(echo 1);then echo "same"; else echo "different";fi
same
Your problem
You could then do something like this for your original problem:
if cmp -s switchshow_reference switchshow_results; then
diff switchshow_reference switchshow_results \
| mail -s device_PORT_ERROR email_recipient
fi
UPDATE #1
In looking at your updated script you need to make the following modifications:
ssh test@ip_of_device switchshow > switchshow_results
variable=$(diff switchshow_reference switchshow_results)
if [[ $variable -eq 0 ]]
then
echo $"nothing"
else
echo -n "$variable" | mail -s switch_HARDWARE_CHECK recipeint_email_address
fi
The issues you were running into with the output showing up as a single line were caused by your use of echo
without telling it to expand special characters, such as, \n
. For example:
$ echo "oneline\ntwoline"
oneline\ntwoline
$ echo -e "oneline\ntwoline"
oneline
twoline
One other modification I made was in how you executed the diff
. This didn't impact your functionality in a bad way, but the backticks (\
..`) has been deprecated in favor of this notation,
$(...)`. These have the added benefit of being able to nest commands inside of other commands such as:
$ myvar=$(echo "good + $(echo bye)")
$ echo $myvar
good + bye
Related videos on Youtube
user46359
Updated on September 18, 2022Comments
-
user46359 over 1 year
I'm new to the world of scripting and and currently using a script to perform a health check on the san devices that I manage.
The script is simple and redirects output of commands to a current file from remote device to my local host. I then use a diff command to compare output of current file and reference file and get a email alert of the difference.
However the problem that I'm currently facing is that every time I run the script, I get a email after the script is executed, that is even if there is no difference in the comparison, I get a blank email from the script execution.
As this is related to performing a automated health check, getting a blank email everyday will be a nuisance. Is there any way of tweaking the diff or add some more code to make sure that when there is no difference showing from the diff, I should not get a email and only get a email if there is a difference and showing the difference.
current script
### saves output of command switchshow in a file on local host ssh user@ip_of_switch switchshow > switchshow_results ### Compares current output to reference file and mails the difference diff switchshow_reference switchshow_results \ | mail -s device_PORT_ERROR email_recipient
Please let me know if any other information is required.
Thanks for the help and details explanation Slm :)
I have so far got the email part working (I get an email only if there is a difference from
diff
command). However the email that I now get has its test concatenated into one long string, which is bad for viewing and not easy to understand for the people who will be getting it.My current script is pasted below:
ssh test@ip_of_device switchshow > switchshow_results variable=`diff switchshow_reference switchshow_results` if [[ $variable -eq 0 ]] then echo $"nothing" else echo $variable | mail -s switch_HARDWARE_CHECK recipeint_email_address fi
The output of the above script is blank and I don't get any email when the
diff
command does not find any difference. However when thediff
commands finds a difference, I get a email as pasted below:16c16 < 0 0 010000 id N4 Online FC F-Port 1 N Port + 1 NPIV public --- > 0 0 010000 id N4 No_Light FC F-Port 1 N Port + 1 NPIV public 26c26 < 10 10 010a00 id N4 Online FC F-Port 1 N Port + 1 NPIV public --- > 10 10 010a00 id N4 No_Light FC F-Port 1 N Port + 1 NPIV public 29c29 < 13 13 010d00 id N4 Online FC F-Port 50:06:01:67:3b:20:23:0a --- > 13 13 010d00 id N4 No_Light FC F-Port 50:06:01:67:3b:20:23:0a
This should ideally look like this in the email..
16c16 < 0 0 010000 id N4 Online FC F-Port 1 N Port + 1 NPIV public --- > 0 0 010000 id N4 No_Light FC F-Port 1 N Port + 1 NPIV public 26c26 < 10 10 010a00 id N4 Online FC F-Port 1 N Port + 1 NPIV public --- > 10 10 010a00 id N4 No_Light FC F-Port 1 N Port + 1 NPIV public 29c29 < 13 13 010d00 id N4 Online FC F-Port 50:06:01:67:3b:20:23:0a --- > 13 13 010d00 id N4 No_Light FC F-Port 50:06:01:67:3b:20:23:0a
Output should display one line at a time in the email. Any suggestions?
-
Marki over 9 yearsI'd suggest you get acquainted with Nagios, Icinga, and the like ;-)
-
-
user46359 over 10 yearsThanks for the Help SLM :) I have made a lot of progress , but I am currently stuck at one last thing. I have edited the above question with my new info. Can you please look into it and help me out? Your help will be much appreciated.