6

I'm putting together a complex pipeline, where I want to include stderr in the program output for recordkeeping purposes but I also want errors to remain on stderr so I can spot problems.

I found this question that asks how to direct stdout+stderr to a file and still get stderr on the terminal; it's close, but I don't want to redirect stdout to a file yet: The program's output will be consumed by other scripts, so I'd like it to remain on stdout (and same for stderr). So, to summarize:

  • Script produces output in fd 1, errors in fd 2.
  • I want the calling program to rearrange things so that output+errors appear in fd 1, errors in fd 2.
  • Also, errors should be interleaved with output (as much as their own buffering allows), not saved and added at the end.

Due-diligence notes: Capturing stderr is easy enough with 2>&1. Saving and viewing stdout is easy enough by piping through tee. I also know how to divert stdout to a file and direct stderr through a pipe: command 2>&1 1>fileA | tee fileB. But how do I duplicate stderr and put stdout back in fd 1?

1 Answer 1

5

As test to generate both stdout and stderr, let's use the following:

{ echo out; echo err >&2; }

The following code demonstrates how both stdout and stderr can be sent to the next step in the pipeline while also sending stderr to the terminal:

$ { echo out; echo err >&2; } 2> >(tee /dev/stderr) | cat >f
err
$ cat f
out
err

How it works

  • 2>

    This redirects stderr to the (pseudo) file which follows.

  • >(tee /dev/stderr)

    This is process substitution and its acts as a pseudo-file that receives input from stderr. Any input it receives is sent to the tee command which sends it both to stderr and to stdout.

Sign up to request clarification or add additional context in comments.

5 Comments

Right, process substitution! That's how to direct non-stdout to a pipe... But what's the point of >&1 in the tee subprocess? Looks like it just makes stdout into a copy of stdout.
Also, sending errors to /dev/tty will probably work, but it's not what I was hoping for-- if I ever need to capture "standard error" into a file, I'll have my hands full of the script's guts.
Looks like 2> >(tee /dev/stderr) does exactly what I needed, though. Thanks!
@alexis Good suggestion! I updated the answer to go to /dev/stderr.
Thanks a lot. I was using x=$(some_function | tee /dev/stderr) and testing success using PIPESTATUS but that doesn't work. But with your solution it works.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.