1
votes

I know there are many similar questions. But, none of the scenario satisfy my requirement.

I have a cron which backup MySQL databases. Currently, I redirect stderr to Slack and stdout to syslog like this:

mysql-backup.sh 1> >(logger -it DB_BACKUP) 2> >(push-to-slack.sh)

This way, we are instantly notified about any errors during backup process. And stdout is kept in syslog, but the stderr are missing from the syslog.

In short, I need stdout+stderr in syslog (with date, PID etc) and pipe (or redirect) stderr to push-to-slack.sh

Any solutions without using temporary files are expected.

1
So mysql-backup.sh 1> >(logger -it DB_BACKUP) 2> >(logger -it DB_BACKUP_STDERR && push-to-slack.sh) doesn't work?jared_mamrot

1 Answers

2
votes

This sends stderr to push-to-slack.sh while sending both stderr and stdout to logger:

{ mysql-backup.sh 2>&1 1>&3 | tee >(push-to-slack.sh); } 3>&1 | logger -it DB_BACKUP

Reproducible Example

Let's create a function that produces both stdout and stderr:

$ fn() { echo out; echo err>&2; }

Now, let's run the analog of our command above:

$ { fn  2>&1 1>&3 | tee err_only; } 3>&1 | cat >both
$ cat err_only 
err
$ cat both
out
err

We can see that err_only captured only the stderr while both captured both stdout and stderr.

(Note to nitpickers: Yes, I know that cat above "useless" but I am keeping the command parallel to the one the OP needs.)

Without using tee

If you really seriously can't use tee, then we can do something like using shell:

{ fn  2>&1 1>&3 | (while read -r line; do echo "$line" >&3; echo "$line"; done >err_only); } 3>&1 | cat >both

Or, using awk:

{ fn  2>&1 1>&3 | awk '{print>"err"} 1'; } 3>&1 | cat >both