55

Is there a way to pipe the output of a command and direct it to the stdout as well?

So for example, fortune prints a fortune cookie to stdout and also pipes it to next command:

$ fortune | tee >(?stdout?) | pbcopy 
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and
the Ugly)."
(By Matt Welsh)
user14492
  • 853

3 Answers3

51

tee always writes to its standard output. If you want to send the data to a command in addition to the terminal where the standard output is already going, just use process substitution with that command. (Note that in spite of starting with >, process substitution does not redirect standard output, the tee command sees it as a parameter.)

fortune | tee >(pbcopy)
31

Your assumption:

fortune | tee >(?stdout?) | pbcopy

won't work because the fortune output will be written to standard out twice, so you will double the output to pbcopy.

In OSX (and other systems support /dev/std{out,err,in}), you can check it:

$ echo 1 | tee /dev/stdout | sed 's/1/2/'
2
2

output 2 twice instead of 1 and 2. tee outputs twice to stdout, and tee process's stdout is redirected to sed by the pipe, so all these outputs run through sed and you see double 2 here.

You must use other file descriptors, example standard error through /dev/stderr:

$ echo 1 | tee /dev/stderr | sed 's/1/2/'
1
2

or use tty to get the connected pseudo terminal:

$ echo 1 | tee "$(tty)" | sed 's/1/2/'
1
2

With zsh and multios option set, you don't need tee at all:

$ echo 1 >/dev/stderr | sed 's/1/2/'
1
2
nullstd
  • 13
cuonglm
  • 153,898
  • 3
    tee $(tty) Or, y'know, tee /dev/tty – Kenster Mar 30 '16 at 12:59
  • great explanation, top SO answer all around. – Merlin Jan 06 '20 at 16:44
  • How come when you do ... tee /dev/stdout | sed... it returns 2 2 and not 1 2; doesn't tee run before sed? It makes no sense, especially since rest print what is expected at that point in pipe. Why is there a wormhole in the pipe? It messing me up man! – user14492 Jul 19 '20 at 01:55
  • @user14492 not sure what you mean. ... tee /dev/stdout causes result to be written to standard out twice, that's why you see 2 2. – cuonglm Jul 20 '20 at 07:00
1

cuonglm said it all.

Just try:

fortune | tee "$(tty)" | pbcopy

tty should resolve to actual pseudo terminal (like /dev/pts/99) in interactive session (i.e. in terminal), or no a tty in batch, at and daemon.

cuonglm
  • 153,898
Archemar
  • 31,554
  • I'm not sure why, but echo "$(tty)" → /dev/pts/2, seq 2 | tee "/dev/pts/2" | wc -l → 1 2 2, but seq 2 | tee "$(tty)" | wc -l → 2 – Pablo A Aug 16 '21 at 21:01
  • 1
    @PabloA yes "$(tty)" (quoted or not) resolv to not a tty. I am not sure how I tested it 5 years ago. – Archemar Aug 18 '21 at 08:15