3

I want to do something like this:

echo 'foo' | tee /dev/stdout > >(cat)

where the stdout from echo gets sent to the terminal and to the cat process. Is there a simpler way to do this?

When I run this:

 echo 'foo' | tee >(echo 'bar')

for some reason, it does not echo 'foo' it only echoes 'bar', why?

8
  • echo 'foo' | tee >(echo 'bar') prints bar and foo for me. Sep 18, 2019 at 20:56
  • that's so weird b/c it doesn't for me, I am on MacOS, maybe tee is different here Sep 18, 2019 at 20:58
  • 3
    @KamilMaciorowski It's absolutely pointless to argue about that; it's all about the order in which the echo foo, echo bar and tee commands will be started and finished, and that's unpredictable. If echo bar finishes before tee tries to write anything into its pipe, tee will be killed by a SIGPIPE.
    – user313992
    Sep 18, 2019 at 21:10
  • 2
    You do it exactly the way that you have shown, but the command in the process substitution should read what's written to it, or it may terminate too early. Sep 18, 2019 at 21:16
  • 1
    echo foo | tee >(echo bar; cat >/dev/null) in your second example
    – user313992
    Sep 18, 2019 at 21:21

3 Answers 3

9

You do it exactly the way you have shown:

somecommand | tee >(othercommand)

The output of somecommand would be written to the input of othercommand and to standard output.

The issue with your echo 'bar' process substitution is that it doesn't care about the input that comes via tee from echo 'foo', so it just outputs bar as quickly as it can and terminates. The tee utility then tries to write to it, but fails and therefore terminates (from receiving a PIPE signal) before it writes the string to standard output. Or, tee may have time to write the data to the process substitution, in which case both bar and foo would be printed on standard output, it's not deterministic.

You need to make sure that the command in the process substitution actually reads the data sent to it (otherwise, what would be the point of sending it data?) As Uncle Billy suggests in comments, this is easily arranged in your example by letting the process substitution simply use cat >/dev/null (assuming you're not interested in the data coming from tee):

echo 'foo' | tee >(cat >/dev/null; echo 'bar')

or

echo 'foo' | tee >(echo 'bar'; cat >/dev/null)

(these two variations would vary only in the order of the final output of the two strings)

1
  • somecommand | tee >(othercommand); cmd3 is problematic in several shell implementations including bash in that othercommand is not waited for, so its output may come after the output of cmd3 for instance. { cmd1 3>&- | tee /dev/fd/4 4>&1 >&3 3>&- | cmd2 3>&-; } 3>&1 would not have the problem and would work with POSIX sh on systems with /dev/fd/x Oct 2, 2019 at 9:21
0

The accepted answer wasn't very clear to me, as the result is piped to /dev/null, obscuring if the pipe worked.

To practice confirming the value is passed, you can cat or use tr on the piped value like this:

% echo foo | tee >(tr -d '\n') ; echo bar
foo
foobar
1
  • As far as I can tell, all you’ve done here is provide an example (and not a very good one) of the accepted answer. Sep 13, 2022 at 0:27
-1
echo 'foo' | tee /dev/tty |other-program
6
  • 1
    That would not really put foo on standard output though. Sep 18, 2019 at 21:38
  • yeah and not always looking for /dev/tty, just to stdout, whatever it may be Sep 18, 2019 at 21:40
  • It does. Test it: echo 'foo' | tee /dev/tty |wc
    – bitinerant
    Sep 18, 2019 at 21:40
  • Try putting your command in a script,  and then running the script with stdout redirected. Sep 19, 2019 at 0:01
  • Sorry - I misunderstood the OP.
    – bitinerant
    Sep 19, 2019 at 6:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .