Bash script - store stderr in a variable [duplicate]

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 separately store stderr in a variable $result ?


Solution 1:

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.

Solution 2:

For any generic command in Bash, you can do something like this:

{ error=$(command 2>&1 1>&$out); } {out}>&1

Regular output appears normally, anything to stderr is captured in $error (quote it as "$error" when using it to preserve newlines). To capture stdout to a file, just add a redirection at the end, for example:

{ error=$(ls /etc/passwd /etc/bad 2>&1 1>&$out); } {out}>&1 >output

Breaking it down, reading from the outside in, it:

  • creates a file description $out for the whole block, duplicating stdout
  • captures the stdout of the whole command in $error (but see below)
  • the command itself redirects stderr to stdout (which gets captured above) then stdout to the original stdout from outside the block, so only the stderr gets captured