107

All the usages of tee I ever saw were such:

 do_something | tee -a logfile

Or:

do_something_else | tee logfile

Is tee invented for those that don't know you can do the same with shell pipe redirections? Such as:

do_something >> logfile

Or:

do_something_else > logfile

It's practically the same and it takes less keyboard hits to type out. What hidden features am I not seeing in tee?

R Moog
  • 1,122

10 Answers10

254

What you don't see is that do_something | tee -a logfile puts the output into logfile and to stdout, while do_something >> logfile puts it only into the logfile.

The purpose of tee is to produce a one input, multiple output scenario - just like in a 'T' crossing.

EDIT

There have been comments around how tee enables more seemless use of sudo. This is beside the point: cat, dd or maybe better buffer provide this possibility with better performance, if you don't need the multiple outputs. Use tee for what it is designed, not for what it "can also do"

Eugen Rieck
  • 20,637
123

Tee is not useless

Maybe you knew that anyway? If not, read on! Or if you know how it works, but aren't sure why it exists, skip to the end to see how it fit in the with the Unix philosophy.

What is the purpose of tee?

At its simplest, it takes data on standard input and writes that to standard output and one (or more) files. It has been likened to a plumbing tee piece in the way it splits one input into two outputs (and two directions).

Examples

Let's take your first example:

do_something | tee -a logfile

This takes the output of do_something and appends it to logfile, while also displaying it to the user. In fact, the Wikipedia page on tee has this as the second example:

To view and append the output from a command to an existing file:

  lint program.c | tee -a program.lint

This displays the standard output of the lint program.c command at the computer and at the same time appends a copy of it to the end of the program.lint file. If the program.lint file does not exist, it is created.

The very next example has another use: escalation of permissions:

To allow escalation of permissions:

cat ~/.ssh/id_rsa.pub | ssh admin@server "sudo tee -a /root/.ssh/authorized_keys2 > /dev/null"

This example shows tee being used to bypass an inherent limitation in the sudo command. sudo is unable to pipe the standard output to a file. By dumping its standard out stream into /dev/null, we also suppress the mirrored output in the console. The command above gives the current user root access to a server over ssh, by installing the user's public key to the server's key authorization list.

Or perhaps you want to take the output of one command, write that somewhere and also use that as input to another command?

You can also use tee command to store the output of a command to a file and redirect the same output as an input to another command.

The following command will take a backup of the crontab entries, and pass the crontab entries as an input to sed command which will do the substitution. After the substitution, it will be added as a new cron job.

$ crontab -l | tee crontab-backup.txt | sed 's/old/new/' | crontab –

(credit to Tee command usage examples)

Tee works with the Unix philosophy:

Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.

(Credit to Basics of the Unix Philosophy)

tee fits all of these:

  • it does one thing: creates an extra copy of input
  • it works with other programs because it is the glue (or a 'T' plumbing piece if you prefer) that lets other programs work together as in the examples above
  • it does this by manipulating a text stream given on standard input
bertieb
  • 7,543
72

It's practically the same and it takes less keyboard hits to type out.

It is not the same at all...

The following appear to be somewhat equivalent, but they're not:

$ echo "hi" > test.txt
$ echo "hi" | tee test.txt
hi

The critical difference is that the former has written the data only to the named file, while the latter has written hi to the terminal (stdout) and the named file, as shown below:

redirect vs tee


tee allows you to write the data to a file and use it in an onward pipeline, allowing you to do useful things - like keeping data from partway through a pipeline:

grep '^look ' interesting_file.txt \
  | tee interesting_lines.txt \
  | sort

Or, you can write to a file with elevated privileges, without giving the whole pipeline elevated privileges (here echo and the shell are running as the user, while tee writes to the file as root):

echo 0 \
  | sudo tee /proc/sys/net/ipv4/ip_forward

With tee, you can write to many files (and stdout):

echo "hi" \
  | tee a.txt b.txt

It's also possible to use exec with tee to record all of a script's output to a file, while still allowing an observer (stdout) to see the data:

exec > >( tee output.log )
Attie
  • 20,734
30

This is a tee:
enter image description here

A T-shaped pipe fitting. It has an inlet, and two separate outlets.
In other words, it splits one pipe into two; like a fork in the road.

Similarly, tee is a pipe (|) that allows you to redirect your standard input to two separate outputs.


Example
Say for instance, you type ls /.
You'll get an output that looks something like:

Applications    Network     Users       bin        dev      net      private    tmp         var
Library         System      Volumes     cores      etc      home     opt        sbin        usr

Redirect the output to a text file, ls / > ls.txt, and no output is displayed in the shell, only in the resulting text file.

Want to see the output, AND pass it to a text file at the same time?
Add a tee to your pipe (|) ie: ls / | tee ls.txt


Compare the two:

ls /          >          ls.txt
ls /        | tee        ls.txt
voices
  • 2,881
18

No. You happen to mention one of the few examples where you could indeed redirect to the file using > and >> operators.

But Tee can do much more. Because you pipe to it, you can then pipe to something else.

A good example is listed on the wikipedia page:

find "4DOS" wikipedia.txt | tee 4DOS.txt | sort > 4DOSsorted.txt

Basically, you can pipe to Tee, so you can then pipe from Tee to something else. If all you want to do is write a log file, yes, then you don't really need Tee.

LPChip
  • 66,193
18

tee is far from useless. I use it all the time and am glad it exists. It's a very useful tool if you have a pipeline that you want to split up. A very simple example is that you have some directory $d that you want to tar and you also want to hash it because you're paranoid (like I am) and don't trust the storage medium to hold the data reliably. You could write it to the disk first and then hash it, but that'd fail if the archive gets corrupted before it's hashed. Furthermore, you'd have to read it and if you work on files that are several hundred GB in size a lot, you will know that you really don't want to read them again if it doesn't have to be.

So what I do is simply this:

tar -c "$d" | tee >(sha256sum) >(cat > "$d"".tar") > /dev/null

It creates the tar ball and pipes it to tee which then pipes it to two sub-shells, in one of which it's hashed and in the other of which it's written to the disk.

It's also great if you want to perform several operations on a big file:

< file.tar.gz tee >(sha256sum) >(tar -xz) /other/storage/location/file.tar.gz > /dev/null

Reads the file once, hashes it (so you can check whether it's still as it should be), extracts it, and copies it to a different location. No need to read it three times for that.

UTF-8
  • 678
12

Nitpick on @bertieb's answer that says This example shows tee being used to bypass an inherent limitation in the sudo command. sudo is unable to pipe the standard output to a file.

There is no inherent limitation, only a misunderstanding of how the command is processed.

Example:

sudo echo 0 > /proc/sys/net/ipv4/ip_forward

The current shell parses the command line. It finds the output redirection and performs that. Then it executes the command, which is the sudo and provides the remaining command line as arguments to the executed command. If the current shell does not have root permissions, then the output redirection will fail.

echo 0 | sudo tee /proc/sys/net/ipv4/ip_forward

This works because the output redirection is deferred to the tee command, which at that point does have root permissions because it was executed via sudo.

sudo bash -c "echo 0 > /proc/sys/net/ipv4/ip_forward"

This works because the shell doing the redirection has root permissions.

studog
  • 363
10

As other people have mentioned, piping output to the tee command writes that output to both a file and to stdout.

I often use tee when I want to capture output from a command that takes a long time to run, while also wanting to visually inspect the output as the command makes it available. That way, I don't have to wait for the command to finish running before I inspect the output.

What doesn't seem to have been mentioned yet (unless I missed it), is that the tee command can also write to multiple files at once. For example:

ls *.png | tee a.txt b.txt

will write out all the *.png files in the current directory to two different files (a.txt and b.txt) at once.

In fact, you can type text to several different files at once with tee like this:

$ tee --append a.txt b.txt c.txt d.txt
These lines are appended to four different files,
and are also written to stdout.
CTRL-D
J-L
  • 211
9

The most common use of tee is to see the text on the terminal at the same time you send it to the file (or files). The wording of your question assumes you only ever write text to logfiles. I have scripts which write lists of filenames or directory names to trigger files (to be processed by other scripts asynchronously) and I use tee to send the same content to stdout. All stdout is directed to the logs. So I have my text where I want it and I have a log entry recording that I did this, all from a single 'echo' statement

tee is also the best method in Unix for making multiple identical files. I use it occasionally for making multiple empty files, like this ...

:|tee file01 file02 file03
1

Imagine, you want to write the output of a command to a log file AND print to stdout. When you need to do it at the same time, then you need tee.

A use case is to have build scripts that write the whole build to stdout (e.g. for Jenkins) but important stuff at the same time to a separate log file (for summary emails).

You'll really start missing tee when you have to script in Windows. There is no tee and that is really annoying.

domih
  • 125