I would like to run a bash script on the target server, whenever any command execution fails, I would like to first send email with error details and why it failed and then exit from the program
I have tried redirecting the whole bash script execution to a log file and sending email the log file.
Right now I am getting email with the file.log content only when the script is executed successfully, but I would like to receive email even when it failed also, with the details. Pleas help.
exec > file.log 2>&1
case $(hostname) in
abcd|defg)
blah
blah
;;
ghij|klmn)
blah
eg: command failed here due to file not present
blah
;;
*) echo "Not found"
esac
echo -e "Sending $(cat file.log)" | mailx -s "Status" abcd#abcd.com
Try this:
I don't know what command you are using so I used PING:
#!/bin/bash
status() {
for hosts in 192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.250; do
ping -t 1 -c 1 "$hosts";
if [[ "$?" -gt "0" ]]; then
echo -e "Host is down: '$hosts'" >> error.log
fi
done
}
failedornot() {
while read line; do
grep -q "down" error.log
if [[ $? -eq "0" ]]; then
echo -e "Something went wrong, sending e-mail report to: abcd#abcd.com"
cat error.log | mailx -s "Status" abcd#abcd.com
rm error.log
else
echo "Everything is fine, executing blabla.sh"
fi
done < error.log
}
status
failedornot
Output
Host is down: 192.168.1.250
Something went wrong, sending e-mail report to: <username>..
Related
Code works fine until the last for loop.
It tries to login database. Either, it establish a successful connection with database or not, script gives output OK/NOT OK depending to the connection and then exit the shell script. What should I do to solve this?
#!/bin/bash
read -p 'Username: ' var_username
read -sp 'Password: ' var_password
filename="$1"
while read -r line; do
name=$(sed 's/#.*$//g; s/(.*$//g; s/=.*$//g; s/).*$//g')
done < "$filename"
#retval=$? | tail -n1|grep OK
for tns in $name
do
tnsping $tns
if [ $? -eq 1 ]; then
echo $tns 'tnsping i calismiyor' >>tnslatest.log
else
echo $tns 'tnsping i calisiyor' >>tnslatest.log
working_tns+=($tns)
fi
done
#The following lines do not work properly.#
for working in $working_tns
do
echo "exit" | sqlplus -L $var_username/$var_password#$working | grep
Connected > /dev/null
if [ $? -eq 0 ]
then
echo "OK"
else
echo "NOT OK"
fi
done
For example; my tnsnames.ora file contains 4 tns.
So, I want to have for output like OK or NOT OK in total.
Thanks in advance.
I've been using cronic to silence emails from cron jobs when the job is successful. I'm trying to customize it so when a response code is 0 and the error output matches a string of "mount: /VessRAID/RH: /dev/sde1 already mounted on /VessRAID/RH.", to not send an email. Below is the script, then the contents of the email then my attempt at trying to suppress the email which is not working. Any idea what I may be doing wrong?
#!/bin/bash
# Cronic v3 - cron job report wrapper
# Copyright 2007-2016 Chuck Houpt. No rights reserved, whatsoever.
# Public Domain CC0: http://creativecommons.org/publicdomain/zero/1.0/
set -eu
TMP=$(mktemp -d)
OUT=$TMP/cronic.out
ERR=$TMP/cronic.err
TRACE=$TMP/cronic.trace
set +e
"$#" >$OUT 2>$TRACE
RESULT=$?
set -e
PATTERN="^${PS4:0:1}\\+${PS4:1}"
if grep -aq "$PATTERN" $TRACE
then
! grep -av "$PATTERN" $TRACE > $ERR
else
ERR=$TRACE
fi
if [ $RESULT -ne 0 -o -s "$ERR" ]
then
echo "Cronic detected failure or error output for the command:"
echo "$#"
echo
echo "RESULT CODE: $RESULT"
echo
echo "ERROR OUTPUT:"
cat "$ERR"
echo
echo "STANDARD OUTPUT:"
cat "$OUT"
if [ $TRACE != $ERR ]
then
echo
echo "TRACE-ERROR OUTPUT:"
cat "$TRACE"
fi
fi
rm -rf "$TMP"
Here is what the email notification looks like:
Cronic detected failure or error output for the command:
/usr/local/sbin/reg-backup-cronic.sh daily
RESULT CODE: 0
ERROR OUTPUT:
mount: /VessRAID/RH: /dev/sde1 already mounted on /VessRAID/RH.
STANDARD OUTPUT:
/dev/sde1 on /VessRAID/RH type ext4 (rw,relatime)
Here is my attempt at a wrapper script:
#!/bin/bash
/usr/local/sbin/reg-backup.sh $1
CODE=$?
err=$TRACE
if [[ $CODE -eq 0 && $err = "mount: /VessRAID/RH: /dev/sde1 already mounted on /VessRAID/RH." ]]
then
exit $CODE
fi
Alas the emails continue.
Hat tip to the creator of cronic, Chuck Houpt, for cluing me in to an answer, which was to look at the original script and why the error is happening. Case-sensitivity got the best of me:
if mount | grep Vessraid; then
echo starting $1 backup >> /var/log/vessraid.log
Notice the case in VessRAID should have been:
if mount | grep VessRAID; then
echo starting $1 backup >> /var/log/vessraid.log
Now emails only happen when there really is an error.
I have a pre-commit hook script to check for TaskID in log message. I'm unable to make out the logic for same. In Highlighted **if** statement i need a logic to check if first letter of first line is TaskID:(multiple digits)-(space)(log message)
Pre-commit hook:
REPOS="$1"
TXN="$2"
# Check log message for proper task/bug identification
if [ -x ${REPOS}/hooks/check_log_message.sh ]; then
${REPOS}/hooks/check_log_message.sh "${REPOS}" "${TXN}" 1>&2 || exit 1
fi
exit 0
=======>>>>>check_log_message.sh
#!/bin/bash
REPOS="${1}"
TXN="${2}"
SVNLOOK=/usr/bin/svnlook
LOG_MSG_LINE1=`${SVNLOOK} log -t "${TXN}" "${REPOS}" | head -n1`
**if (echo "${LOG_MSG_LINE1}" | egrep '^[T][a][s][k][I][D][:]?[-][1-9]
[\s]*.*$' > /dev/null;) \
|| (echo "${LOG_MSG_LINE1}" | egrep '^[a-zA-Z]+[-][1-9][0-9]*[:]?[\s]*.*$'
> /dev/null;)**
then
exit 0
else
echo ""
echo "Your log message does not contain a TaskID(or bad format used)"
echo "The TaskID must be the first item on the first line of the log
message."
echo ""
echo "Proper TaskID format--> TaskID:xxx- 'Your commit message' "
exit 1
fi
I guess your question concerns using conditionals in Bash.
You can work with the exit codes of programs directly.
For example, if egrep matches something, it exits with code 0 which means success,
otherwise it exits with non-zero,
which means failure.
And you can use this is in conditions, for example:
if command; then
echo success
else
echo failure
fi
Where command can be a pipeline, for example:
if ${SVNLOOK} log -t "${TXN}" "${REPOS}" | head -n1 | egrep -q ^TaskID:
then
exit 0
fi
This means if the first line of the log starts with TaskID:, then exit with 0. Instead of an if statement, you could also use a shorter form with && like this:
${SVNLOOK} log -t "${TXN}" "${REPOS}" | head -n1 | egrep -q ^TaskID: && exit 0
In both examples I used -q with egrep, to suppress the output (the matched line), as I guess you probably don't need it.
The full script with the more complete pattern:
#!/bin/bash
REPOS="${1}"
TXN="${2}"
SVNLOOK=/usr/bin/svnlook
${SVNLOOK} log -t "${TXN}" "${REPOS}" | head -n1 | egrep -q '^TaskID:[0-9][0-9]*- ' && exit 0
echo ""
echo "Your log message does not contain a TaskID(or bad format used)"
echo "The TaskID must be the first item on the first line of the log
message."
echo ""
echo "Proper TaskID format--> TaskID:xxx- 'Your commit message' "
exit 1
Alternatively, I modified my script with help of a colleague.
REPOS="$1"
TXN="$2"
# Make sure that the log message contains some text.
SVNLOOK=/usr/bin/svnlook
LOGMSG=$($SVNLOOK log -t "$TXN" "$REPOS")
# check if any comment has supplied by the commiter
if [ -z "$LOGMSG" ]; then
echo "Your commit was blocked because it have no comments." 1>&2
exit 1
fi
#check minimum size of text
if [ ${#LOGMSG} -lt 15 ]; then
echo "Your Commit was blocked because the comments does not meet minimum length requirements (15 letters)." 1>&2
exit 1
fi
# get TaskID by regex
TaskID=$(expr "$LOGMSG" : '\([#][0-9]\{1,9\}[:][" "]\)[A-Za-z0-9]*')
# Check if task id was found.
if [ -z "$TaskID" ]; then
echo "" 1>&2
echo "No Task id found in log message \"$LOGMSG\"" 1>&2
echo "" 1>&2
echo "The TaskID must be the first item on the first line of the log message." 1>&2
echo "" 1>&2
echo "Proper TaskID format--> #123- 'Your commit message' " 1>&2
exit 1
fi
I'm using a script to modify some mailboxes on a Zimbra server hosted on a Ubuntu server. This script checks if mailbox exists and, if so, proceeds the required change.
I get the error
scriptname.sh: 4: Syntax error: Bad fd number
Here's the script:
#!/bin/bash
email=$1
echo "Looking for $email"
/opt/zimbra/bin/zmprov ga "$email" displayName > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Mailbox not found on this server"; exit 2;
fi
/opt/zimbra/bin/zmprov ModifyAccount "$email" zimbraMailTransport smtp:server.domain.com:25
if [ $? -ne 0 ]; then
echo "Error updating Transport.";
exit 3;
fi
echo "Transport updated";
The error is related to this line:
/opt/zimbra/bin/zmprov ga "$email" displayName > /dev/null 2>&1
I'm quite a newbie on bash, so.. I don't really know how to debug this.
For an unknown reason, a \r was added at the end of each line of the script.. Removed it with notepad++, and it worked like a charm. – Ashina
We run daily Selenium tests to test our website and extensions. I wrote a script (according to this question) to count the number of passed and failed tests. Here is the script:
#!/bin/bash
today=`TZ='Asia/Tel_Aviv' date +"%Y-%m-%d"`
yesterday=`TZ='Asia/Tel_Aviv' date +"%Y-%m-%d" -d "yesterday"`
...
print_test_results()
{
declare -i passed_tests=0
declare -i failed_tests=0
declare -i total_tests=0
log_suffix="_${file_name}.log"
yesterday_logs="${log_prefix}${yesterday}_[1,2]*${log_suffix}"
today_logs="${log_prefix}${today}_0*${log_suffix}"
for temp_file_name in $yesterday_logs $today_logs ; do
total_tests+=1
if grep -q FAILED "$temp_file_name" ; then
failed_tests+=1
elif grep -q OK "$temp_file_name" ; then
passed_tests+=1
else
failed_tests+=1
fi
done
echo "<tr>"
echo "<td>$test_name - $today</td>"
if [ $passed_tests = "0" ]; then
echo "<td>$passed_tests passed</td>"
echo "<td><span style=\"color: red;\">$failed_tests failed</span></td>"
else
echo "<td><span style=\"color: green;\">$passed_tests passed</span></td>"
echo "<td>$failed_tests failed</td>"
fi
echo "<td>$total_tests tests total</td>"
echo "</tr>"
}
file_name="chrome_gmail_1_with_extension_test"
test_name="Chrome Gmail 1 With Extension Test"
print_test_results
...
But the problem is, if the files are not there (in $yesterday_logs $today_logs), I get error messages. How do I redirect these error messages to /dev/null? I want to redirect them to /dev/null from the script, and not from the line calling the script - I want this script to never show error messages about files which don't exist.
Just for the record:
In general, to suppress error messages in bash, use command 2>/dev/null. So in your case you should use grep -q OK 2>/dev/null.
But as your case also shows (from what I read in the comments) this is a risky thing to do, as it cloaks errors you might have in your code. "I want this script to never print error messages" should only be said when one knows all possible error cases which could possibly occur.
Inside your script you can place this line at start:
shopt -s nullglob
This will not match anything if your glob pattern doesn't find any matching file. Otherwise whole glob pattern is returned when you use something like:
for temp_file_name in $yesterday_logs $today_logs; do ... done
Eventually I changed this line to:
for temp_file_name in `ls $yesterday_logs $today_logs 2>/dev/null` ; do
total_tests+=1
if grep -q FAILED "$temp_file_name" ; then
failed_tests+=1
elif grep -q OK "$temp_file_name" ; then
passed_tests+=1
else
failed_tests+=1
fi
done
Then only the ls errors are directed to /dev/null.