Ubuntu – the difference between cat and tee

Apache2command lineemailPHP

I was playing around with the Apache php.ini and got it so when I send emails with a PHP file that has the mail() function it will save the email on my computer, which is good for testing and for web developers. This is the line of code I added in the php.ini:

sendmail_path = "cat > /home/cam/Documents/TestEmails/`date '+%Y-%m-%d - %H-%M-%S'`.eml"

Also this line of code worked too:

sendmail_path = "tee > /home/cam/Documents/TestEmails/`date '+%Y-%m-%d - %H-%M-%S'`.eml"

What are the difference between the cat and tee commands?

Best Answer

TL;DR: cat reads from files whose names you pass it, but tee writes to them. Only when you pass no filenames to them do they have the same effect. Otherwise, using tee when you mean cat can overwrite files you meant to read, causing accidental data loss.

cat and tee behave alike when you don't give them any filenames. That's what's happening in your example; the commands have output redirections (>) but no actual command-line arguments. When you do pass the cat and tee commands filenames, they behave differently from one another, and you can even accidentally overwrite files and lose data by passing their names to tee when you meant to pass them to cat.

The reason cat and tee do the same thing without any arguments, but different things with filenames passed as arguments, can be discerned by considering the behavior of each. In general, they have almost opposite behavior. cat reads potentially many files and sends their output to one place, while tee reads one input and sends it to potentially many files.

cat

cat copies the content of all its input files to standard output, one after the other. This is to say that it concatenates the files. For example, cat x y outputs the contents of x followed by the contents of y. When passed a single filename, it copies that file's contents to standard output and then, since it has no more arguments, stops.

When you run cat with no filenames, it defaults to reading from its own standard input. Basically, that means it reads whatever is piped or redirected to it, or otherwise whatever is typed into a terminal. (Another way of putting this is that, with no filenames, cat behaves like cat -, since cat, like various other commands, treats - specially and takes it to designate standard input.)

tee

tee copies the content of its standard input to all of its output files as well as its own standard output. This is to say that it functions like a T-junction--or, more precisely, N T-junctions where N is the number of output files whose names you pass to it. For example, tee x reads its input, writes it to the file x, and also writes it to its own standard output. tee x y reads its input, writes it to the file x and also to the file y, and also writes it to its own standard output.

The most common use of tee is to insert it into a pipeline with a single filename argument. For example, suppose you were piping the output of a command called foo to the input of a command called bar. You could write foo | bar. But if you also wanted to log the output to a file called logfile so you could inspect it, you could use foo | tee logfile | bar.

tee overwrites the files whose names you give it, unless you pass it the -a option, in which case it appends to them. For example, to append to that log instead of overwriting it, you could use foo | tee -a logfile | bar.

Unlike cat, the tee command doesn't treat getting no filename arguments as a special case. Instead, simply writes its input to all zero of the files whose names you gave it, and then passes it along to its standard output as usual. The effect is that, as with cat, running tee with no filenames also copies standard input to standard output.

Culture favors cat when you just want to copy stdin to stdout.

While you can use either cat or tee with no arguments for this purpose, if you use cat then people will know what you mean. tee without arguments is fine, but it looks like a mistake. Sometimes this is described by saying that cat is the idiomatic way to do it.

Note also that the command-line options supported by cat and tee are different. You would probably expect this, since they mostly do different things, and thus are capable of having their behavior customized in totally different way. See man cat and man tee for details, especially about this.

Related Question