views:

213

answers:

3

I'm writing a script to backup a database. I have the following line:

mysqldump --user=$dbuser --password=$dbpswd  \
   --host=$host $mysqldb | gzip > $filename

I want to assign the stderr to a variable, so that it will send an email to myself letting me know what happened if something goes wrong. I've found solutions to redirect stderr to stdout, but I can't do that as the stdout is already being sent (via gzip) to a file. How can I seperately store stderr in a variable $result ?

+4  A: 

Try redirecting stderr to stdout and using $() to capture that. In other words:

VAR=$((your-command-including-redirect) 2>&1)

Since your command redirects stdout somewhere, it shouldn't interfere with stderr. There might be a cleaner way to write it, but that should work.

Edit:

This really does work. I've tested it:

#!/bin/bash                                                                                                                                                                         
BLAH=$((
(
echo out >&1
echo err >&2
) 1>log
) 2>&1)

echo "BLAH=$BLAH"

will print BLAH=err and the file log contains out.

Adam Crume
I don't think this works. stderr is redirected to stdout, which is then redirected to a file. You can't redirect the command's stdout to a file and then replace the displayed stdout with stderr
Michael Mrozek
@Michael: See my edit.
Adam Crume
Works perfectly. Thanks!
thornate
A: 

dd writes both stdout and stderr:

$ dd if=/dev/zero count=50 > /dev/null 
50+0 records in
50+0 records out

the two streams are independent and separately redirectable:

$ dd if=/dev/zero count=50 2> countfile | wc -c
25600
$ cat countfile 
50+0 records in
50+0 records out
$ mail -s "countfile for you" thornate < countfile

if you really needed a variable:

$ variable=`cat countfile`
msw
+2  A: 

You can save the stdout reference from before it is redirected in another file number (e.g. 3) and then redirect stderr to that:

result=$(mysqldump --user=$dbuser --password=$dbpswd  \
   --host=$host $mysqldb 3>&1 2>&3 | gzip > $filename)

So 3>&1 will redirect file number 3 to stdout (notice this is before stdout is redirected with the pipe). Then 2>&3 redirects stderr to file number 3, which now is the same as stdout. Finally stdout is redirected by being fed into a pipe, but this is not affecting file numbers 2 and 3 (notice that redirecting stdout from gzip is unrelated to the outputs from the mysqldump command).

Edit: Updated the command to redirect stderr from the mysqldump command and not gzip, I was too quick in my first answer.

hlovdal