7

I've a script which do. ls , cp, mv I want if any of the command fail this should alert over email as well as after successful competition. Any idea? I can adjust email alert but want to know how to check for errors and successful attempt.

1
  • Looks like you want to keep track of access to your server. This is not the best way to set restrictions or logging. An alternative for ls would be find -maxdepth 1 -ls, mv/cp could be replaced by a python/perl script or a combination with tar. Of course, it's possible to place your own binaries on the system and execute them. What would you like to accomplish?
    – Lekensteyn
    Mar 27, 2011 at 19:50

4 Answers 4

5

You can have a series of commands continue to execute until "failure" by using "&&" to run the commands in succession; each command returns "true", causing the following command to run. Then use "||" to run a command upon failure, such as:

#!/bin/bash

cp foo bar \
  && mv bar bar{,.bak} \
  && echo "good so far" \
  && ls file123 | tee -a /tmp/msg.txt \
  && mailx -u user -s "success" -f /tmp/msg.txt \
  ||  mailx -u user -s "failure" -f ~/err.txt

Since that can get messy, use functions, such as

#!/bin/bash

do_work() {
  mv... || return 1
  cp... || return 1
  return 0
}

report() {
  [ "$1" = "ok" ] && mailx ....
  [ "$1" != "ok" ] && mailx -s "$1" ....
  return 0
}

do_work \
  && report ok 
  || report err

Further, continuing from the above example, you can add blanket rules via a 'trap' in the script that will always execute certain commands if any type of error status is returned at any point in the script (including receiving a control-c (interrupt) signal while the script is running):

#!/bin/bash
tmp=/tmp/msg.$$.txt

# Cleanup: delete tmp files on exit. On any error, trap and exit... then cleanup
trap 'echo "cleaning up tmpfiles..." && rm $tmp >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 15

...

do_work && exit 0

(Disclaimer... commands shown above are general pseudo-code, and just typed from memory without running them. Typos surely exist.)

1
  • Nice. I like how clean this answer is. Start dead simple, move on to a slightly cleaner way to do it.
    – jorfus
    Nov 22, 2016 at 18:43
6

Bash doesn't have any built in alerting for this stuff, you need to write it into your script by checking the $? variable (holds the exit code of the last run command) and taking an action on it.

A dead simple check that emails would look like:

if [ $? -ne 0 ]
then
    <send me email however you want to about failure>
else
    <send me email about success how ever you want> 
fi

Be sure to check your command documentation to make sure successful execution sets an exit code of 0.

1
  • 1
    belatedly, fwiw, bash does have a "exit on any error" feature built-in (set -e, same as another answer suggests by using shabang #!/bin/bash -e), upon which event (trap) you could perform a specific action like sending an email. But it's not always going to work the way one expects, so a more manual condition handling is generally preferred, as described in this answer (checking an exit status via $?, || and/or &&). mywiki.wooledge.org/BashFAQ/105
    – michael
    Aug 1, 2017 at 0:23
4

You use a mailwrap command wrapper, one which takes some options specifying who to mail to, before running the command which is its parameter. The mailwrap command only sends email if there's output, or if the script failed. There are many variants out there, and they're good exercises to write yourself if you don't like those you find.

On the #! line of the script itself, you use -e, so that any command pipeline which fails causes the script to abort at that point. You might also use -u, to abort on using an unset variable.

To have a failing command not abort the script, you append || true, read as "or true", so that failure doesn't matter. (More idiomatically, || : which is the same thing).

If you want to see exactly where a normally-silent command failed, you use a mailwrap command which doesn't send email just because of output to stderr and then you use -v on the shell #! line, to trace commands as they're about to be run.

1

Or pipe the output of the script into a mail whatever the result is until you're happy it's working.

Something like:

(cat $resultofscript) | mailx -s "Subject" [email protected]

You must log in to answer this question.

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