0

Is it possible to pipe normal stdout further to another program, but store stderr into a variable?

This is the usecase:

mysqldump database | gzip > database.sql

In this scenario I would like to catch all errors/warnings produced by mysqldump and store them into a variable, but the normal stdout (which is the dump) should continue being piped to gzip.

Any ideas about how to accomplish this?

lockdoc
  • 1,539
  • 1
  • 18
  • 31

2 Answers2

3

You can do the following:

mysqldump database 2> dump_errors | gzip > database.sql
error_var=$( cat dump_errors )
rm dump_errors

Here, all errors by mysqldump are redirected to a file called 'dump_errors', and stdout is piped to gzip, which in turn writes to database.sql.

Contents of 'dump_errors' are then assigned to variable 'error_val', and file 'dump_errors' is then removed.


Note the following redirections:

$ sort 1> output 2> errors   # redirects stdout to "output", stderr to "errors"
$ sort 1> output 2>&1        # stderr goes to stdout, stdout writes to "output"
$ sort 2> errors 1>&2        # stdout goes to stderr, stderr writes to "errors"

$ sort 2>&1 > output         # tie stderr to screen, redirect stdout to "output"
$ sort > output 2>&1         # redirect stdout to "output", tie stderr to "output"
assefamaru
  • 2,751
  • 2
  • 10
  • 14
  • 1
    Is this possible without the need of an extra file? – lockdoc Feb 24 '16 at 11:53
  • Check out muru's solution. In general, if you want to use pipes, then you can't create variables within the pipes since the pipe runs in a subshell and variables will not persist once you exit, hence the need for the extra file. But if you don't use a pipe, then you can do away with the extra file. – assefamaru Feb 24 '16 at 12:15
  • Thanks for your additional information. However, I am going to accept muru's answer as it does all stuff without tmpfies. – lockdoc Feb 24 '16 at 15:32
2

You could do something like:

errors=$(mysqldump database 2>&1 > >(gzip > database.sql))

Here, I'm using process substitution to get gzip to use mysqldump's output as stdin. Given the order of redirections (2>&1 before >), mysqldump's stderr should now be used for the command substitution.

Testing it out:

$ a=$(sh -c 'echo foo >&2; echo bar' 2>&1 > >(gzip > foo))
$ gunzip < foo
bar
$ echo $a
foo
Community
  • 1
  • 1
muru
  • 4,723
  • 1
  • 34
  • 78
  • Is it also possible to store both exit codes and both error messages (of `mysqldump` and also of `gzip`) so I can check on them separately afterwards? – lockdoc Feb 24 '16 at 12:28
  • @lockdoc not using this way, I'm afraid. You can get `mysqldump`'s exit codes using `$?`, but the `gzip` status is lost. – muru Feb 24 '16 at 12:32