21

As far as I know, I can use the tee command to split the standard output onto the screen and further files:

command -option1 -option2 argument | tee file1 file2 file3 

Is it possible to redirect the output to commands instead of files using tee, so that I could theoretically create a chain of commands?

Rob
  • 441
  • 3
    Explain what you mean by "output signal" and describe what you mean by creation of a "network of commands". – Janis Mar 08 '15 at 21:37
  • in linux each command has one input and two outputs. they are labeled with 0 (for input) , 1 (for output) and 2 (for error output) . I was thinking of 1 when i said "output signal" because I read that the tee command splits only the output labeled 1. When I said "network of commands" I was not very technical, I am not sure how network is defined correctly from a mathematical point of view, but I was simply thinking of a tree of commands typologically speaking, so that some commands can be parents to more than one child command. – Abdul Al Hazred Mar 09 '15 at 00:17
  • Thanks for your clarification. Please don't use the word signal since it has a specific meaning in Unix, and the term was very misleading in this context. Thanks again. – Janis Mar 09 '15 at 10:47
  • At the command-line enter man -k signal to learn the special meaning of this key concept in UNIX and Linux. man kill would be a good page to start on. – Rob Mar 09 '15 at 16:13
  • Also, many people refer to stdin stdout and stderr as input or output 'streams'. There are like small rivers of data hence a stream. You were correct to grapple for a word to describe them collectively but signal is just the wrong word. – Rob Mar 09 '15 at 16:19

4 Answers4

24

You could use named pipes (http://linux.die.net/man/1/mkfifo) on the command line of tee and have the commands reading on the named pipes.

mkfifo /tmp/data0 /tmp/data1 /tmp/data2
cmd0 < /tmp/data0 & cmd1 < /tmp/data1 & cmd2 < /tmp/data2 &
command -option1 -option2 argument | tee /tmp/data0 /tmp/data1 /tmp/data2

When command finishes, tee will close the named pipes, which will signal an EOF (read of 0 bytes) on each of the /tmp/dataN which would normally terminate the cmdN processes. Real example:

$ mkfifo /tmp/data0 /tmp/data1 /tmp/data2
$ wc -l < /tmp/data0 & wc -w < /tmp/data1 & wc -c < /tmp/data2 &
$ tee /tmp/data0 /tmp/data1 /tmp/data2 < /etc/passwd >/dev/null
$ 61
1974
37

Because of the background processes, the shell returned a prompt before the program output. All three instances of wc terminated normally.

Arcege
  • 22,536
15

If I understand correctly, you're looking for the equivalent of tee file1 file2 file3, but rather than write the same data to three files file1, file2 and file3, you want to pipe the same data into three commands cmd1, cmd2 and cmd3, i.e.

… | ??? cmd1 cmd2 cmd3

should be equivalent to

… | cmd1 &
… | cmd2 &
… | cmd3 &

except that would only be executed once.

There are two ways to do that.

Ksh93, bash and zsh support process substitution. This is a generalization of pipes that allows the argument of a command to be a file that, when written to, passes data as input to a command (there is also the input variant which, when read from, obtains data output by a command). That is,

echo hello | tee >(cmd1)

prints hello to standard output and in addition runs cmd1 with hello as input.

So for example, if you want to duplicate the input of somecommand and pass it to both cmd1 and cmd2, you can use

somecommand | tee >(cmd1) | cmd2

If your shell doesn't support process substitution, you can use named pipes instead. See Arcege's answer for how that works. Named pipes are less convenient than process substitution because you have to create them and delete them, and start and synchronize processes manually. They have the advantage of being fully portable, whereas not all shells support process substitutions. They can also be used in scenarios other than the ones process substitution is for.

Under the hood, on some systems, process substitution uses named pipes internally. On most systems, though, it relies on named files representing file descriptors.

6

At least in you can skip mkfifo using process substitution:

command -option1 -option2 argument | tee >(cmd1) >(cmd2) >(cmd3)

or to adopt Arcege's example

tee >(wc -l) >(wc -w) >(wc -c) < /etc/passwd >/dev/null
3

I'm surprised no one has mentioned the pee command from moreutils (https://joeyh.name/code/moreutils).

Lexelby
  • 111
  • 2