1

This post basically asks the same question but I want an additional requirement, which is: the exit code should be unchanged.

The accepted answer uses pipe, so the exit code is no longer the exit code of command1.

Command set pipefail doesn't fit my need as I don't want to affect the behavior when executing command1, which might be a compound Bash command itself.

I tried the following approach, but the output is not as expected:

[hidden]$ (echo haha; echo hehe 1>&2) > >(while read -r x; do echo "xx $x"; done)
2> >(while read -r y; do echo "yy $y"; done)
xx haha
xx yy hehe

Can anyone tell why?

Community
  • 1
  • 1
Kan Li
  • 8,557
  • 8
  • 53
  • 93

3 Answers3

0

The reason why you get xx yy hehe in your output because yy hehe line from 2nd while loop is also being written on stdout and being fed to the first while read loop thus becoming xx yy hehe

You can use this script:

{ echo haha; echo hehe >&2; } 2> >(while read -r y; do echo "yy $y"; done) > >(while read -r x; do echo "xx $x"; done)
yy hehe
xx haha

EDIT: To show how exit code remains unchanged this way:

{ echo haha; ls hehe >&2; } 2> >(while read -r y; do echo "yy $y"; done) > >(while read -r x; do echo "xx $x"; done); echo "exit status: $?"
xx haha
yy ls: cannot access hehe: No such file or directory
exit status: 2

EDIT2 To show how to use alternate file descriptors for redirecting:

{ date >&5; ls hehe >&6 2>&6; } \
5> >(while read -r x; do echo "xx: $x"; done) \
6> >(while read -r y; do echo "yy: $y"; done); \
echo "exit status: $?"; 5>&- && 6>&-
xx: Sat Dec  6 03:25:20 EST 2014
yy: ls: cannot access hehe: No such file or directory
exit status: 2
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • if the two process substitutions output to stderr, then it still has problem. Try `{ echo haha; echo hehe >&2; } 2> >(while read -r y; do echo "yy $y"; done >&2) > >(while read -r x; do echo "xx $x"; done >&2)` – Kan Li Dec 06 '14 at 06:25
  • @icando: I did't get your comment. You asked how to redirect stdout and stderr separately and my suggested command does that. Now if those commands redirect to stderr again then of course same read script (`yy` in that case) will get data again from fd `2`. I don't see anything unexpected in this case. – anubhava Dec 06 '14 at 06:46
  • @Jasen: No where in this script `exit` code is tampered. Run this command: `echo haha; ls hehe >&2; } 2> >(while read -r y; do echo "yy $y"; done) > >(while read -r x; do echo "xx $x"; done); echo $?` and will you will see exit code `2` which is originating from `ls` command. – anubhava Dec 06 '14 at 06:49
0

This was answered back in 2012. The reason is because the substitutions are not all done at the same time. A workaround is to keep stderr with stderr.

foo > >(baz) 2> >(qux 1>&2)
Zombo
  • 1
  • 62
  • 391
  • 407
0

I found the answer myself:

command1 3>&1 4>&2 1> >(command2 1>&3 2>&4) 2> >(command3 1>&3 2>&4)

In this way, no matter command2 and command3 output to stdout or stderr, there will be no problem.

Kan Li
  • 8,557
  • 8
  • 53
  • 93
  • With your example in the question, my answer gives the exact output as this, and is less verbose – Zombo Dec 06 '14 at 08:46