Guidelines

This site is for tech Q&A. Please keep your posts focused on the subject at hand.

Ask one question at a time. Don't conflate multiple problems into a single question.

Make sure to include all relevant information in your posts. Try to avoid linking to external sites.

Links to documentation are fine, but in addition you should also quote the relevant parts in your posts.

0 votes
433 views
433 views

I have a script with an error handler and output redirection to syslog:

#!/bin/bash

error_handler() {
  echo "Unexpected error ${1} in ${2}, line ${3}, ${4}(): ${5}"
  exit "${1:-1}"
}
set -eETuo pipefail
trap 'error_handler "$?" "$0" "$LINENO" "${FUNCNAME[0]:-main}" "$BASH_COMMAND"' ERR

exec > >(logger -p local0.err -t foo -e --id="$$") 2> >(logger -p local0.err -t foo -e --id="$$")

# rest of the script here

This works fine and logs both regular output as well as errors to syslog. However, now I would like to run the script as a cron job and get notified when the job fails. Cron by default sends notifications whenever a cron job produces output, but the redirection causes the script to be completely silent.

I could add ... | tee /dev/tty or ... >/dev/tty to error_handler() so that termination messages would appear on the console, but cron jobs don't have a terminal, so this would only work when running the script interactively.

Of course I could change the script so that the error handler itself would send the e-mail

from="root@$(hostname -f)"
to='me@example.org'
echo "Unexpected error ${1} in ${2}, line ${3}, ${4}(): ${5}" |
  tee /dev/stderr |
  mailx -r "$from" -c '' -s "$0 failed" "$to"

but that would require an additional program for something that cron can already do by itself.

How can I get my script to generate error output for cron (to trigger failure e-mails) while still logging the full output to syslog?

in Scripting
edited by
by (125)
3 19 33
edit history

Please log in or register to answer this question.

1 Answer

0 votes
 

You need to preserve the un-redirected stdout in a different file descriptor before redirecting it to syslog:

exec 3>&1 > >(logger ...) 2> >(logger ...)

Note: the order in which the redirections occur in this line matters!

With the un-redirected stdout preserved as fd 3 you can then restore it in your error handler:

error_handler() {
  exec 1>&3
  echo "Unexpected error ${1} in ${2}, line ${3}, ${4}(): ${5}" | tee /dev/stderr
  exit "${1:-1}"
}

The tee command duplicates the termination message to stderr (which is still redirected to syslog), so that the message goes to both cron and syslog.

by (125)
3 19 33
edit history
...