--- /dev/null
+#!/usr/bin/env bash
+#
+# mail-wrapper -- Report results of a command by email
+# Copyright (c)2017 Alexander Barton (alex@barton.de)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+
+NAME=$(basename "$0")
+
+# Include "ax-common.sh":
+ax_common_sourced=
+for dir in "$HOME/lib" "$HOME/.ax" /usr/local /opt/ax /usr; do
+ [ -z "$ax_common_sourced" ] || break
+ ax_common="${dir}/lib/ax/ax-common.sh"
+ # shellcheck source=/usr/local/lib/ax/ax-common.sh
+ [ -r "$ax_common" ] && . "$ax_common"
+done
+if [ -z "$ax_common_sourced" ]; then
+ echo "Error ($(basename "$0")): \"ax-common.sh\" not found, aborting!"
+ echo "Please install 'ax-unix', \"Alex' UNIX Tools & Scripts\", and try again."
+ exit 99
+fi
+unset dir ax_common ax_common_sourced
+
+usage() {
+ echo >&2
+ echo "Usage:" >&2
+ echo " $NAME [--help|--usage]" >&2
+ echo " $NAME {parameters} [<command> [<arg> [<…>]]]" >&2
+ echo >&2
+ echo " -C Use the \"C\" locale, no localized (error) messages." >&2
+ echo " --errors|-e Generate email on errors only." >&2
+ echo " --from|-f Email address of the sender of the email." >&2
+ echo " --subject|-s <subject> Subject for the email." >&2
+ echo " --to|-t <address> Email address to send the email to." >&2
+ echo >&2
+ echo "When no <command> is given, $NAME reads from standard input." >&2
+ echo >&2
+ exit "${1:-0}"
+}
+
+syntax_error() {
+ ax_error -l "Syntax error!"
+ usage 2
+}
+
+# Initialize internal state.
+unset is_error
+host=$(hostname -f 2>/dev/null || hostname)
+
+# Some defaults (can be adjusted by command line parameters).
+unset do_errors_only
+unset subject
+from="${LOGNAME:-root} <${LOGNAME:-root}@$host>"
+to="$from"
+
+# Parse the command line ...
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ "-C")
+ unset LANG
+ export LC_ALL="C"
+ ;;
+ "--debug"|"-D")
+ export DEBUG=1
+ ;;
+ "--errors"|"-e")
+ do_errors_only=1
+ ;;
+ "--from"|"-f")
+ shift
+ [[ $# -gt 0 ]] || syntax_error
+ from="$1"
+ ;;
+ "--help"|"--usage")
+ usage
+ ;;
+ "--subject"|"-s")
+ shift
+ [[ $# -gt 0 ]] || syntax_error
+ subject="$1"
+ ;;
+ "--to"|"-t")
+ shift
+ [[ $# -gt 0 ]] || syntax_error
+ to="$1"
+ ;;
+ "-"*)
+ syntax_error
+ ;;
+ *)
+ # Command to execute follows in command line.
+ break
+ ;;
+ esac
+ shift
+done
+
+# Initialize the "buffer file" on file handle #3. This file will store all
+# output, stdout and stderr combined. The file is immediately unliked so that
+# we can't leak stale files. Afterwards this script accesses the "buffer file"
+# by its file descriptor only.
+buffer_file=$(mktemp) \
+ || ax_abort -l "Failed to create buffer file: \"$buffer_file\"!"
+ax_debug "buffer_file=\"$buffer_file\""
+exec 3>"$buffer_file" \
+ || ax_abort -l "Failed to redirect FD #3 to buffer file!"
+rm "$buffer_file" \
+ || ax_error -l "Failed to delete buffer file: \"$buffer_file\"!"
+buffer_file="/dev/fd/3"
+
+if [[ $# -gt 0 ]]; then
+ # Execute command and save output in buffer file.
+ # Use a sub-shell to not pollute our name space!
+ error_file=$(mktemp) \
+ || ax_abort -l "Failed to create error buffer file: \"$error_file\"!"
+ ax_debug "error_file=\"$error_file\""
+ exec 4>"$error_file" \
+ || ax_abort -l "Failed to redirect FD #4 to error file!"
+ rm "$error_file" \
+ || ax_error -l "Failed to delete error buffer file: \"$error_file\"!"
+ error_file="/dev/fd/4"
+
+ job=$(basename "$1")
+
+ ax_debug "Running command \"$*\" ..."
+ exit_code=$(
+ "$@" 2>&1 1>&3 | tee "$error_file" >&3
+ echo "${PIPESTATUS[0]}"
+ )
+else
+ # Read from stdin and save it to the buffer file.
+ error_file="/dev/null"
+ job="Job"
+
+ ax_debug "Reading from stdin ..."
+ while read -r line; do
+ echo "$line" >&3 \
+ || ax_abort -l "Failed to write to buffer file!"
+ done
+ exit_code=0
+fi
+
+ax_debug "exit_code=$exit_code"
+
+count_all=$(wc -l <"$buffer_file" || ax_abort -l "Failed to count buffer file!")
+count_err=$(wc -l <"$error_file" || ax_abort -l "Failed to count error file!")
+
+# Error or no error -- that's the question! An error is assumed when either the
+# exit code of the command was non-zero or there was output to stderr.
+[[ $count_err -gt 0 || $exit_code -ne 0 ]] && is_error=1
+
+# Construct email subject ...
+[[ -z "$subject" ]] && subject="$host: $job report"
+[[ -n "$is_error" ]] && subject="$subject - ERROR!" || subject="$subject - success"
+
+ax_debug "from=\"$from\""
+ax_debug "to=\"$to\""
+ax_debug "subject=$subject"
+
+if [[ -n "$DEBUG" ]]; then
+ echo "--- stdout+stderr ---"
+ cat "$buffer_file"
+ echo "--- stderr ---"
+ cat "$error_file"
+ echo "---"
+fi
+
+ax_debug "count_all=$count_all"
+ax_debug "count_err=$count_err"
+ax_debug "is_error=$is_error"
+
+# No errors detected (exit code & stderr), and email should be sent on errors
+# only: so exit early!
+[[ -z "$is_error" && -n "$do_errors_only" ]] && exit $exit_code
+
+# No error detected and no output at all: skip email, exit early:
+[[ -z "$is_error" && $count_all -eq 0 ]] && exit $exit_code
+
+# Build the report mail.
+# Make sure to ignore all mail(1) configuration files, system wide /etc/mailrc
+# (by using the "-n" option) as well as ~/.mailrc (by setting the MAILRC
+# environment varialbe).
+export MAILRC=/dev/null
+(
+ echo "$job report:"
+ echo
+ echo " - Host: $host"
+ echo " - User: $(id -un)"
+ echo " - Exit code: $exit_code"
+ echo
+ if [[ $# -gt 0 ]]; then
+ # A command name is known (not stdin), show it!
+ echo "Command:"
+ echo "$@"
+ echo
+ fi
+ if [[ $count_err -gt 0 ]]; then
+ # Prefix mail with all error messages.
+ echo "Error summary:"
+ echo "-----------------------------------------------------------------------------"
+ cat "$error_file" \
+ || ax_abort -l "Failed to dump error file!"
+ echo "-----------------------------------------------------------------------------"
+ echo
+ fi
+ if [[ $count_all -ne $count_err ]]; then
+ # Show full output when different to "error output" only.
+ cat "$buffer_file" \
+ || ax_abort -l "Failed to dump buffer file!"
+ fi
+) | mail -n -a "From: $from" -s "$subject" "$to" \
+ || ax_abort -l "Failed to send email to \"$to\"!"
+
+exit $exit_code