40

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)
1
  • 1
    I don't have my OSX at hand, what about fortune | tee $(tty) | pbcopy?
    – Archemar
    Mar 30, 2016 at 12:24

3 Answers 3

39

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)
2
  • This is good, also a good solution.
    – Merlin
    Jan 6, 2020 at 16:43
  • 1
    ~~Does anyone know what this redirection look like in fish shell?~~ The docs say 'There is no equivalent to >(command).'
    – user14492
    Jun 30, 2021 at 0:17
25

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
4
  • 2
    tee $(tty) Or, y'know, tee /dev/tty
    – Kenster
    Mar 30, 2016 at 12:59
  • great explanation, top SO answer all around.
    – Merlin
    Jan 6, 2020 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, 2020 at 1: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, 2020 at 7: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.

2
  • 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, 2021 at 21:01
  • @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, 2021 at 8:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.