2

Right now I have this:

 echo "$run_test" | bash 2>&1 | prepend "r2g-test:" "yellow"; 

What this does is prepend "r2g-test:" to each line of the stdout/stderr. Because I am sending stderr to stdout, the prepend program doesn't know the difference because it's all stdin to it.

Is there some way I can send stderr to a different prepend instance, perhaps with tee?

Perhaps something like this?

 echo "$run_test" | bash 2> $(prepend 'r2g-test:' 'red') | prepend 'r2g-test:' 'yellow'; 

This might work, with process substitution:

bash 2> >(prepend 'r2g-test:' 'red') 

But so far, the stderr never shows up in the terminal

4
  • 1
    Possible duplicate of Can I configure my shell to print STDERR and STDOUT in different colors? Commented May 7, 2018 at 7:38
  • Nah this one is more specifically about pipelines, that is more general Commented May 7, 2018 at 7:41
  • No worries. I looked at what you seemed to be trying to achieve rather then the mechanics of one possible solution Commented May 7, 2018 at 8:37
  • Yeah this is pretty tricky stuff np Commented May 7, 2018 at 8:47

1 Answer 1

3

First, let's create a program run_test which generates both stdout and stderr:

$ run_test() { while sleep 0.2; do echo "Out $((++c))"; echo "err$c">&2; done; } 

Now, let's send the stdout and stderr to different filters. Since I don't have a prepend installed, I will use sed for the same purpose:

$ exec 3>&2; { run_test | sed 's/^/stdout: /'; } 2>&1 1>&3 | sed 's/^/stderr: /' stdout: Out 1 stderr: err1 stdout: Out 2 stderr: err2 stdout: Out 3 stderr: err3 

How it works

  • exec 3>&2

    This creates file descriptor 3 as a duplicate of stderr.

  • run_test | sed 's/^/stdout: /'

    This runs run_test and prepends stdout: to the beginning of stdout.

  • { run_test | sed 's/^/stdout: /'; } 2>&1 1>&3

    2>& redirects stderr to stdout so that stderr will go into the next pipe. 1>&3 redirects stdout to stderr so that it appears on the terminal.

  • { run_test | sed 's/^/stdout: /'; } 2>&1 1>&3 | sed 's/^/stderr: /'

    The last pipe captures run_test's stderr, (which is now stdout) and prepends stderr: to it.

Using process substitution

$ run_test > >(sed 's/^/stdout: /') 2> >(stdbuf -oL sed 's/^/stderr: /' >&2) stdout: Out 1 stderr: err1 stdout: Out 2 stderr: err2 stdout: Out 3 stderr: err3 

The above uses stdbuf which is standard on Linux. For other OS's, one will need to look for analogous commands.

14
  • thanks! There must be a simpler way! I saw something like this using an intermediate fd, but I hoping for something less xrazy. What about this: echo "$run_test" | bash 2> >(prepend 'r2g-test:' 'red') | prepend 'r2g-test:' 'yellow'; ... why won't that work? Commented May 7, 2018 at 7:51
  • that uses process substitution, but the stderr never seems to show up in the terminal Commented May 7, 2018 at 7:52
  • 1
    @AlexanderMills I added a solution using process substitution. Note that anytime one one separates the two streams, output order is not guaranteed. Commented May 7, 2018 at 8:00
  • thanks, I asked a new question, because this one was a bit unclear: unix.stackexchange.com/questions/442250/… Commented May 7, 2018 at 8:07
  • nice sed prepending trick by the way, i didn't know that you could do that Commented May 7, 2018 at 8:08

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.