linux - error handling in case sentences [Shell Script]
2014-07
I have this setup and I need when an error happened in the main script, to take this error to a $INFO_PLUGIN temp file, the problem is the script continues working after case
and send also an OK message to $INFO_PLUGIN temp file, overriding existing error message.
I would like to when a error comes, take this error to $INFO_PLUGIN temp file and prevent the execution of reportmail OK;
in some way, but I don't know how and I need some help.
Thnaks in advance for your time and cooperation.
Main Script:
source ~/share/mailReport.fn
case $2 in
firstcase)
ssh -q -n loguser@server "mkdir -p /home/loguser/logstorage"
if [[ $? -ne 0 ]]; then
echo " ************ "
echo " * Error * "
echo " ************ "
reportmail 12;
exit 12;
fi;
;;
secondcase)
startDate=`date +%s`
if [ -z $3 ]; then
echo -e "\nInsert a parameter...: $0 $1 $2 [Here!]\n"
exit;
fi;
echo -e "\nRunning test with error number...: $3\n"
endDate=`date +%s`
DIFF=$(( $endDate - $startDate ))
echo -e "* Time in sec..: $DIFF\n"
reportmail $3;
;;
esac
echo " ************ "
echo " * Finished * "
echo " ************ "
reportmail OK;
reportMail.sh Script:
case $1 in
12)
mailx -s "Error happened during mkdir" -r $SENDER_ADDRESS $RECIPIENT_ADDRESS
<<EOF
Hello,
Error happened in `uname -n` bla, bla, bla...
EOF
echo -e "CRITICAL - Error creating destination dir" > $INFO_PLUGIN
;;
OK)
echo -e "OK - Time in sec..: $DIFF Total Saved..: `cat $temp` MB" > $INFO_PLUGIN
rm $temp
;;
esac
Edit:
############################### Little example ###############################
test.sh
#!/bin/sh
source ~/test2.sh
case $1 in
a) error 0; ;;
b) error 1; ;;
c) error 2; ;;
esac;
error 0; # This is what I need to jump in case of error
test2.sh:
#!/bin/sh
function error () {
case $1 in
0) echo "Everything = OK" > ~/results.txt ;;
1) echo "Sth Wrong = error 2" > ~/results.txt ;;
2) echo "Sth Wrong = error 3" > ~/results.txt ;;
esac;
}
if I run:
[user@server dir]$ ./Test.sh 1
or:
[user@server dir]$ ./Test.sh 2
this is the result, included on file ~/results.txt
[user@server dir]$ cat results.txt
Everything = OK
The result is the same on all cases, because error 0;
on first script, so my question is how can I do to determine if an error happened on some value on first case
, for example: error happened running Test.sh b
. How may I do to jump error 0;
and prevent to execute it if there is an error before, else if there is no error on case
. error 0;
should be executed to say hey, everything is ok!
I hope you understand and thanks a lot for your time.
Problem solved by adding this:
echo -e "CRITICAL - Error deleting files - Performance" > $INFO_PLUGIN && echo "1" > $err
this send a 1
to an error file and...
if [ `cat $err` -eq 1 ]; then
reportmail 201$BYTES;
rm $err
else
reportmail 201$BYTES;
reportmail OK;
rm $err
fi;
this test if there was an error during execution of scripts, if yes, just send the report in ordr to see the log on a web server, otherwise, if everithing is OK send the log to a web server and send OK message to Nagios monitoring system.
Thanks! & until next time!
I wrote the following script to interactively and recursively remove orphan backup files, i.e. remove each file.txt~
that does not have a corresponding file.txt
.
#!/bin/sh -x
set -o errexit
unalias -a
backups=$(find . -name "*~")
orphans=""
while read -r file
do
[ ! -e "${file%~}" ] && orphans=$(echo "$file\n$orphans");
done << EOF
$backups
EOF
if [ -z "$orphans" ]; then
echo "No orphans."
else
echo "orphans:\n$orphans"
echo "$orphans" | xargs --interactive -d '\n' rm
fi
This script does very weird things in a random fashion. Sometimes it behaves correctly, sometimes it ignores the -x options passed to sh, sometimes it executes commented code, sometimes the tests give just wrong results.
The problem seems to be related to the here script, since by redirecting the output of find to a temporary file all problems seem to disappear. But why, where is the error?
Solution (thanks to Dennis Williamson): Escape the ~
character. The unescaped ~
in the parameter expansion ${file%~}
was creating somehow all the unpredictable behavior.
A more readable and deterministic solution, with some fat cut out, could be (thanks to the suggestions of Mikel):
#!/bin/sh
IFS='
'
for backup in $(find . -type f -name "*~"); do
if [ ! -e "${backup%\~}" ]; then
rm -i "$backup"
fi
done
If you are a while read
loop fan, things get less elegant because the interactive command rm -i
can not be used (it will conflict with the read
command). Anyway, a solution could be:
#!/bin/sh
orphans=""
while read -r backup; do
if [ ! -e "${backup%\~}" ]; then
orphans=$(echo "$backup\n$orphans");
fi
done << EOF
$(find . -type f -name "*~")
EOF
if [ ! -z "$orphans" ]; then
echo "$orphans" | xargs --interactive -d '\n' rm
fi
Or, a more complex way is also suggested by Dennis Williamson.
You probably need to escape the tilde in the brace expansion, otherwise it will get expanded to your home directory.
Why don't you pipe the find
into your while
loop instead of creating variables to hold them? Inside your loop, just do rm -i "$file"
.
#!/bin/sh -x
set -o errexit
unalias -a
exec 3<&0 # open a duplicate of stdin
flag=false
find . -name "*~" | while IFS=$'\n' read -r file
do
if [ ! -e "${file%\~}" ]
then
orphans="$file"$'\n'"$orphans"
# use an alternate file descriptor so read and rm -i get along
rm -i "$file" <&3
flag=true
fi
done
exec 3<&- # close the file descriptor
if ! $flag
then
echo "No orphans."
else
echo "orphans:\n$orphans"
fi
If you want to use Bash, you need to move the find
to the end of the loop so a subshell is not created.
#!/bin/bash
...
# use an alternate file descriptor so read and rm -i get along
while read -u 3 -r ...
rm -i ...
...
done 3< <(find ...)
...
What do you mean "sometimes"? Sometimes on the same box? Or different behavior on different systems?
What do you mean "executes commented code"? Your example doesn't have any comments.
Some thoughts:
- try
set -x
in place of/bin/sh -x
better to useset -e
thanset -o errexit
- if you're using bash, then call
/bin/bash
, not/bin/sh
, which could be something else - echo is unnecessary, just use
=
with a literal newline - if you do have to use
echo
, you should useecho -e
or ensurexpg_echo
is set - your orphans line is putting them in reverse order, is that deliberate?
- your read loop will fail if file names contain spaces, you should set
IFS
first
A simpler version:
#!/bin/bash
set -x
set -e
IFS=$'\n'
orphans=false
for backup in $(find . -type f -name "*~"); do
original=${backup%\~}
if [ ! -e "$original" ]; then
orphans=true
rm -i "$backup"
fi
done
if ! $orphans; then
echo "No orphans."
fi
Or if you want it to work using /bin/sh
:
#!/bin/sh
set -x
set -e
IFS='
'
orphans=false
for backup in $(find . -type f -name "*~"); do
original=${backup%\~}
if [ ! -e "$original" ]; then
orphans=true
rm -i "$backup"
fi
done
if ! $orphans; then
echo "No orphans."
fi