Cron: Only get errors in emails?

I finally set up a realistic backup schedule on my data through a shell script, which are handled by cron on tight intervals. Unfortunately, I keep getting empty emails each time the CRON has been executed and not only when things go wrong.

Is it possible to only make CRON send emails when something goes wrong, ie. my TAR doesn't execute as intended?

Here's how my crontab is setup for the moment;

0 */2 * * * /bin/backup.sh 2>&1 | mail -s "Backup status" [email protected]

Thanks a lot!


Solution 1:

Ideally you'd want your backup script to output nothing if everything goes as expected and only produce output when something goes wrong. Then use the MAILTO environment variable to send any output generated by your script to your email address.

[email protected]
0 */2 * * * /bin/backup.sh

If your script normally produces output but you don't care about it in cron, just sent it to /dev/null and it'll email you only when something is written to stderr.

[email protected]
0 */2 * * * /bin/backup.sh > /dev/null

Solution 2:

Using cronic wrapper script looks like a good idea; to use it you don't have to change your scripts.

Instead of:

 0 1 * * * /bin/backup.sh 2>&1 | mail -s "Backup status" [email protected]

do:

 [email protected]
 0 1 * * * cronic /bin/backup.sh

Simply put; it will run silent if everything runs smooth (exit status 0), but it will report verbosely if not, and let cron handle the mail reporting.

More info on https://habilis.net/cronic/.

Solution 3:

Here is another variation that I've successfully utilized for many years - capture output and print it out only on error, triggering an email. This requires no temp files, and preserves all output. The important part is the 2>&1 that redirects STDERR to STDOUT.

Send the entire output via default cron mailer config:

1 2 * * * root OUTPUT=`flexbackup -set all 2>&1` || echo "$OUTPUT"

Same but with a specific address and subject:

(address can also be changed by setting MAILTO=xxxx for the entire crontab file)

1 2 * * * root OUTPUT=`flexbackup -set all 2>&1` || echo "$OUTPUT" | mail -s "Failed to backup" [email protected]

You can even perform multiple actions on error and add to email:

1 2 * * * root OUTPUT=`flexbackup -set all 2>&1` || {echo "$OUTPUT" ; ls -ltr /backup/dir ; }

This will work for simple commands. If you are dealing with complex pipes (find / -type f | grep -v bla | tar something-or-other), then you're better off moving the command into a script and running the script using the aforementioned approach. The reason is that if any part of the pipe outputs to STDERR, you'll still get emails.

Solution 4:

You are specifically instructing cron to always send email, even when /bin/backup.sh (by the way, it should be in /usr/local/bin) succeeds. Just omit the | mail -s "Backup status" [email protected] part and email will only be sent when there is output. You can probably (depending on your cron) explicitly set the email address to mail to as an assignment in the crontab file.

For details, see

man 5 crontab

Solution 5:

You should be directing the stderr anmd not both stdout and stderr.

Use 1> /dev/null not 2>&1 and it should be fine. Also, you may need to report the error correctly in your backup script.