views:

1335

answers:

5

I have a cron job:

$SP_s/StartDailyS1.sh >$LP_s/MirrorLogS1.txt

Where SP_s is the path to the script and LP_s is the path for the log file. This sends stdout to the log file and stderr to my email.

How do I?:
1) send both stdout AND stderr to the logfile,
2) AND send stderr to email

or to put it another way: stderr to both the logfile and the email, and stdout only to the logfile.

UPDATE: None of the answers I've gotten so far either follow the criteria I set out or seem suited to a CRON job.

I saw this, which is intended to "send the STDOUT and STDERR from a command to one file, and then just STDERR to another file" (posted by zazzybob on unix.com), which seems close to what I want to do and I was wondering if it would inspire someone more clever than I:

(( my_command 3>&1 1>&2 2>&3 ) | tee error_only.log ) > all.log 2>&1

I want cron to send STDERR to email rather than 'another file'.

A: 

I assume you are using bash, you redirect stdout and stderr like so

1> LOG_FILE
2> LOG_FILE

to send a mail containing the stderr in the body something like this

2> MESSAGE_FILE
/bin/mail -s "SUBJECT" "EMAIL_ADDRESS" < MESSAGE_FILE

I'm not sure if you can do the above in only one passage as this

/bin/mail -s "SUBJECT" "EMAIL_ADDRESS" <2
Alberto Zaccagni
+1  A: 

If you can do with having stdout/err in separate files, this should do:

($SP_s/StartDailyS1.sh 2>&1 >$LP_s/MirrorLogS1.txt.stdout) | tee $LP_s/MirrorLogS1.txt.stderr
nos
The above sends stdout and stderr to a file, and also sends stderr to stdout (so it'll be mailed if you run from a cron job). So stderr gets in your mail.( I don't know how to send stdout/err to only one file instead of 2 as above - and still send only stderr to mail though)
nos
A: 

A bit tricky if you want stdout and stderr combined in one file, with stderr yet tee'd into its own stream.

This ought to do it (error-checking, clean-up and generalized robustness omitted):

#! /bin/sh

CMD=..../StartDailyS1.sh
LOGFILE=..../MirrorLogS1.txt
FIFO=/tmp/fifo

>$LOGFILE

mkfifo $FIFO 2>/dev/null || :

tee < $FIFO -a $LOGFILE >&2 &

$CMD 2>$FIFO >>$LOGFILE

stderr is sent to a named pipe, picked up by tee(1) where it is appended to the logfile (wherein is also appended your command's stdout) and tee'd back to regular stderr.

pilcrow
A: 

Since I was just looking at the info page for tee (trying to figure out how to do the same thing), I can answer the last bit of this for you.

This is most of the way there:

(( my_command 3>&1 1>&2 2>&3 ) | tee error_only.log ) > all.log 2>&1

but replace "error_only.log" with ">(email_command)"

(( my_command 3>&1 1>&2 2>&3 ) | tee >(/bin/mail -s "SUBJECT" "EMAIL") ) > all.log 2>&1

Note: according to tee's docs this will work in bash, but not in /bin/sh. If your putting this in a cron script (like in /etc/cron.daily/) then you can just but #!/bin/bash at the top. However if your putting it as a one-liner in a crontab then you may need to wrap it in bash -c ""

sherbang
+2  A: 

Not sure why nobody mentioned this.

With CRON if you specify MAILTO= in the users crontab, STDOUT is already sent via mail.

Example

[temp]$ sudo crontab -u user1 -l
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=user1
# transfer order shipping file every 3 minutes past the quarter hour
3,19,33,48 * * * * /home/user1/.bin/trans.sh
basher