How can a command have more than one output?

The cat foo bar example is not what I meant. Here cat only has one input and one output at a time.

tee is an example: it outputs to all the arguments, plus its standard output at the same time. Using the same kind of ASCII art diagram as in my previous answer, here's how tee foo bar looks like when it's operating in a terminal.

   +------------------+    
   |       tee        |    
===|<stdin            |         +------------+
→  |                  |         |  terminal  |
   |           stdout>|=========|<input      |
   |                  |   → ##==|<           |
   |                  |     ||  +------------+
   |           stderr>|=====##
   |                  |   →
   |                  |       +-------------+
   |                3>|=======|> file "foo" |
   |                  |   →   +-------------+
   |                  |       +-------------+
   |                4>|=======|> file "bar" |
   |                  |   →   +-------------+
   |                  |    
   +------------------+    

In this example, tee is sending “useful” output to three channels: to the terminal (because that's where its standard output is connected to), and to two files. In addition, tee has one more output channel for errors.

A program normally has three input/output channels, identified by their file descriptor number:

  • standard input (stdin for short, file descriptor number 0);
  • standard output (stdout for short, file descriptor number 1);
  • standard error (stderr for short, file descriptor number 2).

The purpose of file descriptors 0, 1 and 2 is only a matter of convention — nothing enforces that a program cannot attempt to write to file descriptor 0 or read from descriptors 1 and 2 — but this is a convention that is pretty much universally followed.

If you run a program from a terminal, file descriptors 0, 1 and 2 start out connected to that terminal, unless they have been redirected. Other file descriptors start out closed, and will be used if the program opens other files.

In particular, all commands have two outputs: standard output (for the command's payload, the “useful” output), and standard error (for error or informational messages).

A pipeline in the shell (command1 | command2 | command3 | …) connects each command's standard output to the next command's standard input. All commands' standard error goes to the terminal (unless redirected).

Shells provide ways to redirect other file descriptors. You've probably encountered 2>&1 or 2>file to redirect standard error. See When would you use an additional file descriptor? and the other posts it links to for examples of manipulations of other file descriptors.

Feature-rich shells also offer process substitution to generalize file redirection to piped commands, so that you aren't limited to a linear pipe with each command having a single input and a single output.

Very few commands attempt to access file descriptors above 2, except after they've opened a file (opening a file chooses a free file descriptor and returns its number to the application). One example is GnuPG, which expects to read the data to encrypt/decrypt/sign/verify on its standard input and to write the result to standard output. It can be told to read a passphrase on a different file descriptor with the --passphrase-fd option. GnuPG also has options to report status data on other file descriptors, so you can have the payload output on stdout, error messages on stderr, and status information on another file descriptor. Here's an example where the output of a piped command is used as a passphrase:

echo fjbeqsvfu | rot13 | gpg -d --passphrase-fd=3 3<&0 <file.encrypted >file.plaintext

Yes. For example cat foo bar | less gives two inputs (file foo and file bar) and outputs them both to less. vim foo* will output all files beginning with foo into vim. After reviewing each file you can then switch to the next output with :n (or :wn if you've changed anything). I think Gilles explained it very well. If you are using pipe ( | ) it takes the output of one command, inputs it into another command, and then outputs the result. That's another example of multiple outputs.


Commands can have more than one output stream and I don't mean by writing to files or sockets. Consider most GNU tools (eg. grep) that print errors to stderr and the expected output to stdout. While in a interactive shell both get merged (2>&1), you can still treat them separately. It doesn't end there, since you can use extra file descriptors if the program or code block supports it.

Contrived example:

{
  grep NORMAL log.txt
  grep WARN log.txt 1>&3
  grep ERROR log.txt 1>&4
} 1> normals.txt 3> warnings.txt 4> errors.txt # 2>/dev/null