I have a job for root

0 0 * * * /usr/bin/time /path/to/mysqlbackup.sh | /bin/mail -s "MySQL Backup" "admin@example.com"

And the script will echo out some information when it is run, which is then emailed as expected.

The problem is if an error occurs, it is not being sent to the email, so I'm not able to catch it. If I view the mail of the root user I see errors like

mysqldump: Got error: 2002: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) when trying to connect

How can I make all output caused from the script be sent to my email?


Notes

Cron job

* * * * * (/usr/bin/time /root/utils/test.sh 2&>1) | /usr/bin/tee /tmp/cron.test | /bin/mail -s "test" "srobbins@example.com"

Message found in root's mail

[root@example utils]# mail
Mail version 8.1 6/6/93.  Type ? for help.
"/var/spool/mail/root": 1 message 1 new
>N  1 root@example  Fri Oct 11 08:35  23/1025  "Cron <root@example> (/usr/bin/time /root/utils/test.sh 2&>1) | /usr/bin/tee /tmp/cron.test | /bin/mail -s "test" "srobbins@example.com""
& 
Message 1:
From root@example.com  Fri Oct 11 08:35:01 2013
Date: Fri, 11 Oct 2013 08:35:01 -0700
From: root@example.com (Cron Daemon)
To: root@example.com
Subject: Cron <root@example> (/usr/bin/time /root/utils/test.sh 2&>1) | /usr/bin/tee /tmp/cron.test | /bin/mail -s "test" "srobbins@example.com"
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>

Null message body; hope that's ok

Contents of /root/utils/test.sh

echo "Starting backup at $(date)" 
mysql -u potato -e "show status" # produces error
FILE="/path/to/file.bak"
FILESIZE=`du -h $FILE | cut -f1`
echo $FILESIZE

/tmp/cron.test is empty

The body of the dispatched email is empty

有帮助吗?

解决方案

Basically you need to handle STDERR in the same way as STDOUT.

Pipe it in cron

0 0 * * * (/usr/bin/time /path/to/mysqlbackup.sh 2&>1) | /bin/mail -s "MySQL Backup" "admin@example.com" 

This works on Ubuntu, you reported it doesn't work for you (empty mail body). I'd be interested to dig into that so more, but in the meantime...

Adjust your script

You can make your script only print to STDOUT by redirecting STDERR (at least for that one command to STDOUT)

echo "Starting backup at $(date)" 
mysql -u potato -e "show status" 2>&1 # produces error we want, so redirect it
FILE="/path/to/file.bak"
FILESIZE=`du -h $FILE | cut -f1`
echo $FILESIZE

If you want any error in your script to be sent to STDOUT, you can globally redirect STDERR to STDOUT by adding this at the top of your script:

exec 2>&1

Toy example

job.sh

#prints out to STDOUT and STDERR
echo good
echo error >&2
echo good

script.sh

#this runs job.sh redirecting STDERR to STDOUT
sh job.sh 2>&1

Now running job.sh, with various redirections shows its printing to STDOUT and STDERR

$sh job.sh > /dev/null 
error
$sh job.sh 2> /dev/null 
good
good

running script.sh shows its only printing to STDOUT even though job.sh is printing to STDERR

$sh script.sh > /dev/null 
$sh script.sh 2> /dev/null 
good
error
good

其他提示

You can also use the MAILTO variable :

MAILTO="admin@example.com"
0 0 * * * /usr/bin/time /path/to/mysqlbackup.sh
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top