105

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?

7
  • 64
    How was this not answered by the very first line of the man page "...and write to standard output and files"? The answers are interesting, but broadly talking about how pipes are useful just reinforces how this Q seems too broad, and should perhaps have been closed.
    – Xen2050
    Commented Sep 12, 2018 at 1:17
  • 4
    @Xen2050 A question cannot be blamed for a too-broad answer. The question is very specific, as is the current highest rated answer. Commented Sep 14, 2018 at 9:34
  • 1
    @JonBentley the question doesn't sound like "a specific problem with enough detail to identify an adequate answer" (as the close dialog reads). It does sound like this: "if your question could be answered by an entire book, or has many valid answers (but no way to determine which - if any - are correct), then it is probably too broad for our format." (Source: the Help Center)
    – Xen2050
    Commented Sep 15, 2018 at 8:02
  • 6
    @Xen2050 Are we reading the same question? It seems highly specific to me - what is the difference between tee and pipes? It has been adequately answered using two sentences. Far from an entire book. The fact that some answers choose to go off on a tangent has nothing to do with the scope of the question. Commented Sep 15, 2018 at 10:43
  • @JonBentley: Are we reading the same question?  R Moog kind-of sort-of implies a fairly well focused question — what is the difference between tee and I/O redirection?  The fact that it says “shell pipe redirections such as > and >>” is not a point in its favor, and is an argument for closing as unclear.  But it actually asks multiple questions: “What is the purpose of tee?”, “Is tee invented for those that don’t know you can do the same with shell pipe redirections?” and “What hidden features am I not seeing in tee?”.  At least two of those questions are too broad. Commented Sep 21, 2018 at 2:32

10 Answers 10

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"

13
  • 37
    Multiple output is the key. tee can even take multiple arguments and write to many files at once. Commented Sep 10, 2018 at 11:26
  • 20
    I would call it a tee pipe fitting, not a crossing (as in a road intersection?) Stuff comes in one way and goes out both ways. Commented Sep 11, 2018 at 0:49
  • 8
    How would I use cat in a straightforward way instead of tee in e.g. echo /var/work/core.%p | sudo tee /proc/sys/kernel/core_pattern? echo /var/work/core.%p | sudo cat > /proc/sys/kernel/core_pattern doesn't work, because the redirect is processed by the non-sudo shell. As for dd, echo /var/work/core.%p | sudo dd of=/proc/sys/kernel/core_pattern works, but dd is often an overpowered tool capable of doing great damage, especially under sudo. As for buffer, its not installed by default in any of the RedHat- or Ubuntu-based distros I have to hand (or MacOS)... Commented Sep 15, 2018 at 2:58
  • 4
    @EugenRieck I do get your point about about the 1:n relation between in:out being the primary function. However, neither the builtin cat nor /bin/cat work for me in this situation. It doesn't matter where cat comes from - the > will still be handled by the top level (non-sudo) shell. The advantage of tee over cat in this situation is that it allows the output file to be passed as a command-line param (and not a redirect). dd is certainly a viable option, though I'd still favour tee for this Commented Sep 15, 2018 at 16:15
  • 4
    @EugenRieck What shell has cat and tee as builtins? And what version of sudo can run shell builtins?
    – wjandrea
    Commented Sep 16, 2018 at 4:07
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
5
  • 3
    @Joe: sudo tee -a is probably a more recent innovation (I first saw it in Ubuntu guides / wikis especially for setting stuff in /proc/sys, because switching to Ubuntu was when I switched to a sudo based system (how Ubuntu is configured by default) instead of using su with a root password). I think tee predates sudo, so it's not a reason for tee existing. You don't need tee for that, it's simply shorter to type interactively than sudo sh -c 'cat > output'. Commented Sep 11, 2018 at 5:07
  • 1
    With modern shells like bash, you can tee to feed two pipelines, like foo | tee >(pipe2) | pipe1. Or another fun one is ffmpeg ... |& tee /dev/tty | sed 's/.*\r// > encode.log to see status-line updates interactively on the tty, while removing "lines" that end with carriage-return instead of newline for actual logging. (i.e. filter out the status-line updates). In general, you can stick a tee /dev/tty anywhere in a pipeline as a debug-print. Commented Sep 11, 2018 at 5:13
  • 2
    It's less a limitation of sudo you're working around and more a limitation of the shell's interpretation of >. When you run a command with sudo its stdout gets sent back to your shell program and further redirects with > are run with the shell's permissions. If you want to write with elevated permissions you need to have the elevated part of the pipeline be what does the writing. There are a large number of ways to do this depending on precisely what effect you're going for. If you really want to use > something like 'sudo bash -c "command > outfile" ' will do the job.
    – Perkins
    Commented Sep 12, 2018 at 18:14
  • Exactly, @Perkins. The shell parses the > and sets up the redirection before sudo even get exec'd, so it's definitely not a limitation of sudo that it doesn't handle things it never sees. :) I usually try to refer to this as "the sudo workflow" or some similar term when I'm explaining it, rather than describing sudo itself.
    – dannysauer
    Commented Sep 13, 2018 at 14:19
  • sudo tee -a is IMHO an abuse of tee. Use sudo cat, sudo dd or (with best performance in many cases) sudo buffer if you don't need the multiple outputs. Commented Sep 14, 2018 at 21:29
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 )
7
  • 2
    Not to forget exec > >(tee "$LOGFILE") 2>&1 in a bash script which lets the script output stdout and stderr to both, stdout and the file pointed to by $LOGFILE. Commented Sep 10, 2018 at 13:45
  • @rexkogitans 2>&1 isn't that cmd batch syntax?
    – dmb
    Commented Sep 10, 2018 at 15:06
  • @dmb: It's shell syntax for "send stderr(=2) to the same place as stdout(=1)"
    – psmears
    Commented Sep 10, 2018 at 15:10
  • @rexkogitans It was a fair question really, I can't really know that you haven't used "Windoze" for a decade. I use 2>&1 to drop output and err to txt files in windows.
    – dmb
    Commented Sep 10, 2018 at 15:11
  • 1
    @dmb I am sorry for sounding rude. It's all about psmears' comment. Obviously, Windows adopted Unix-style here. Commented Sep 10, 2018 at 15:23
29

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
4
  • 4
    +1 for picture which as we know is worth a thousand words Commented Sep 14, 2018 at 4:57
  • If you had picked a garden hosepipe T piece, you would have been in line with Doug McIlroy's original metaphor.
    – JdeBP
    Commented Sep 18, 2018 at 16:21
  • @JdeBP Sorry, I have no idea who that is. Is he the original author of the utility or something? The flow of data & physical electrical current are often compared to hydraulic systems, but you probably know that. Anyway, I just chose this style to keep it super simple. I was actually going to do that to keep it familiar, but the garden variety tend to have more of a Y-shape and/or visually complicated attachments for attaching accessories, etc. It's essentially the same though.
    – voices
    Commented Sep 19, 2018 at 17:34
  • 1
    M. Douglas McIlroy, author of this famous memo who worked at Bell Labs and persuaded Ken Thompson to put pipes into Unix.
    – JdeBP
    Commented Sep 20, 2018 at 12:59
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.

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.

13
  • 3
    Nitpick: tee does not create the subshells; the calling shell runs sha5sum and cat and connects their output to file descriptors which are passed to tee. Also, a useless use of cat; you can use input redirection to have tee read directly from file.tar.gz.
    – chepner
    Commented Sep 10, 2018 at 16:09
  • @chepner You're right about the first interjection but you're completely wrong about the second one. I like writing my pipelines in order, so denoting the input at the right is terrible for readability and doing so is clearly objectively inferior to my method and totally not a subjective preference of mine. cat is love. cat is life.
    – UTF-8
    Commented Sep 10, 2018 at 16:59
  • 6
    You can also write < file.tar.gz tee >(sha256sum) ... if you are concerned about the lexical ordering of the redirections. That doesn't change the fact that there is no need for an entirely separate process just to feed a single file to tee.
    – chepner
    Commented Sep 10, 2018 at 17:13
  • 1
    @chepner Cool, thank you! Learned something today. :)
    – UTF-8
    Commented Sep 10, 2018 at 19:34
  • 1
    The cost of starting cat is relatively low. The cost of an extra 100 GiB of write + read system calls definitely wastes extra CPU time and memory bandwidth for your proposed example of a huge file. Remember that memory bandwidth is a shared resource across all cores, not to mention the extra pollution of L3 cache from that copying. On an x86 with Spectre + Meltdown mitigation enabled, system calls are more expensive than they used to be. You're using up a measurable amount of extra CPU time over the course of that copy. Also >(cat > foo) is not easier to understand than foo, IMO. Commented Sep 11, 2018 at 18:16
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.

1
  • 2
    Also, you might need sudo for the command, but not for the file being output and the redirection works just fine: sudo foo-needs-privilege > /tmp/this-output-file-doesnt Commented Sep 11, 2018 at 0:37
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
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
3
  • 5
    why not touch? (more immediately obvious what is happening)
    – Attie
    Commented Sep 10, 2018 at 22:09
  • @Attie touch will not truncate files if they already exist but only update their timestamps and leave their content as is; but tee will truncate them. Also, doing rm+touch is different than tee (think about hardlinks and symlinks) Commented Sep 13, 2018 at 23:29
  • Then why not truncate -s 0? :-)
    – Attie
    Commented Sep 14, 2018 at 7:12
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.

7
  • Isn't it trivial to create? Commented Sep 11, 2018 at 17:50
  • It is not possible with batch/cmd as you can not split a stream of output from a command easily.
    – domih
    Commented Sep 12, 2018 at 8:53
  • Right but like a three-line C++ program... Commented Sep 12, 2018 at 8:59
  • 1
    The Windows unxutils distribution has many Unix command line tools which, unlike some distributions, do not pollute your Windows execution environment. The biggest limitation is on "glob"bing, which works differently on Unix/Linux than on Windows. "tee" is among the tools available.
    – cmm
    Commented Sep 12, 2018 at 13:18
  • 2
    Don't be silly, it's 2018. Use Powershell, it has tee. Cmd was never intended for serious scripting - that's what VBS was for. Powershell is the new go-to scripting tool. Granted, Cmd is still pretty powerful, but the command-line tools are pretty few.
    – Luaan
    Commented Sep 13, 2018 at 7:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .