#!/bin/sh set -eu usage() { cat <<-'EOF' Usage: cronjob COMMAND... cronjob -h EOF } help() { cat <<-'EOF' Options: -h, --help show this message COMMAND the command to be executed Execute the given command, and send the output to email, with special treatment to the status code. It loads the appropriate files, so that the actual cron declaration is smaller. Examples: Run a backup: $ cronjob backup -q cron EOF } for flag in "$@"; do case "$flag" in --) break ;; --help) usage help exit ;; *) ;; esac done while getopts 'h' flag; do case "$flag" in h) usage help exit ;; *) usage >&2 exit 2 ;; esac done shift $((OPTIND - 1)) set +eu # shellcheck source=/dev/null . /etc/profile # shellcheck source=/dev/null . ~/.profile set -eu epoch() { awk 'BEGIN { srand(); print(srand()) }' } now() { date '+%Y-%m-%dT%H:%M:%S%:z' } pre() { # Same as: # sed -u "s|^|[$CMD]: |" # but the "-u" option is not POSIX IFS='' while read -r line; do printf '[%s]: %s\n' "$CMD" "$line" done } duration() { minutes=$((${1} / 60)) seconds=$((${1} % 60)) printf '%sm%ss' "$minutes" "$seconds" } CMD="$*" HOSTNAME="$(hostname)" TIMEOUT='14400' # four hours STATUS_F="$(mkstemp)" OUT="$(mkstemp)" send_email() { FROM="cronjob@$HOSTNAME" TO='root@localhost' SUBJECT="(exit status: $(cat "$STATUS_F")) - $HOSTNAME: $CMD" email -s "$SUBJECT" -f "$FROM" "$TO" < "$OUT" rm -f "$OUT" "$STATUS_F" } trap send_email EXIT { cat <<-EOF Running command: $CMD Start at: $(now) EOF START="$(epoch)" STATUS=0 timeout "$TIMEOUT" nice -n19 ionice -c3 "$@" || STATUS=$? printf '%s' "$STATUS" > "$STATUS_F" END="$(epoch)" DURATION_SECONDS=$((END - START)) cat <<-EOF Finished at: $(now) Duration: $(duration "$DURATION_SECONDS") EOF } 2>&1 | pre | ts '%Y-%m-%dT%H:%M:%S' | tee "$OUT" >> "$XDG_LOG_HOME"/cronjobs.log