Linux: tee Command

In this blog, we'll learn how to use the tee command. But also answer an interesting question. Why do we need tee to redirect (save) a command's output to a file? When we can do the same thing with the > redirect operator?

What does tee bring to the table that > does not have?

How to Use the "tee" Command on Linux

Imagine a simple scenario. We want to upgrade our Ubuntu system with the usual:

sudo apt upgrade

And we want to capture all the output that we get:

We can save all of this text to a file. If something doesn't work after the upgrade, we can later read that file, and try to figure out what went wrong.

To save the output from the previous command, we can use the tee command like this:

sudo apt upgrade | tee upgrade.log

What we did here is called piping (with the | character). We piped (transferred) the output from:

  • sudo apt upgrade
  • To another command: tee upgrade.log

This tells the tee command to pick up the output from the previous command and save it to a file called upgrade.log.

We can choose any file name we want. And if the file does not exist, it will be created automatically.

At first glance, after running this, nothing special seems to happen:

sudo apt upgrade | tee upgrade.log

We will get the same output, and the same "yes" or "no" questions. But, behind the scenes, tee will do its job and save all of this output that we see on our screen.

Let's read the file, and check:

cat upgrade.log

Yes, it's all there, except that WARNING line. But we'll get to that, and explain why it doesn't appear in this file.

So we can conclude that the general syntax of the tee command is something like this:

some command here | tee name_of_output_file
💡
For reference, the package manager on Ubuntu will automatically save some useful output on its own, in the /var/log/apt/ directory.

Why Do We Need the "tee" Command?

With tee you can capture all the output generated by a command, and save it to a file.

At first glance, it might seem that this is not that different from output redirection. I mean, we can run a command like this:

sudo apt update > update.log

Where we use the > character to redirect all output from that command, to a file called update.log.

But notice the problem:

Now we get almost nothing displayed on-screen.

sudo apt update normally generates a lot of output. But this time, it mysteriously disappeared. Usually, when we run this command (without redirecting output), we'll get something like this:

So, one advantage of tee: It lets you SEE the output of the previous command, and at the same time, also saves that output to a file. A "2 in 1" sort of thing.

> "hides" the output from the screen.

And tee actually has a third advantage; so it's more of a "3 in 1": It also lets you interact with the previous command. Meaning:

  • When we use > for redirection, we cannot interact with the command. Cannot "Press y to continue," or stuff like that. Technically, we could still press keys to interact with that program. But since we cannot see any output on the screen, it's unfeasible. We wouldn't know what actions we are taking, and what the results would be if we press those keys.
  • But when we redirect / save output with tee, we can do that. We can still interact normally with that program, press "y" to continue, and so on.

It's still worth mentioning that our previous command, sudo apt update > update.log did its job. The update.log file contains the redirected output.

But for this particular scenario > is not what we needed. It works well when we don't need to see the output of the command, just save it. And when that command is not interactive, doesn't ask us to press any keys, and so on.

The conclusion?

  • For commands that generate non-interactive output, and where we don't need to see that output, just save it to a file, the > operator can be used.
  • But when we need to interact with the previous command, and also need to see its output, we should use tee.

How to Make "tee" Also Save Error Messages (stderr)

If we use a command like this, we'll notice a small issue:

sudo apt update | tee update.log

See that WARNING line of text? Well, if we look at the file where we saved our output, we won't find it:

That's because, by default, tee does not save errors/warning messages.

Normally, this is not a problem. We can see that even in our example here, we don't really need that warning in our update.log file. But, there will be situations where we will actually want to save errors and warnings too.

To understand how to make tee also save error messages, we first have to understand how Linux treats output.

For any program that generates output, that output is split into two types:

  1. Normal output that goes to something called stdout (standard output).
  2. Error messages (and warnings) that go to something called stderr (standard error).

So the command sends normal output to stdout, and errors to stderr. And then the operating system checks to see what these stdout and stderr "are connected to".

If they're "connected to" our terminal window, both streams of text end up there, on-screen. If one is "wired to" our terminal window, but the other is "wired to" a file, then they'll go to different places. Which is exactly what happens when we run a command like sudo apt update | tee update.log.

Essentially, tee will make stdout go to our screen, and our update.log file. But stderr won't get any special treatment. stderr will remain "connected" just to our screen (and not the file). So stderr output will just end up on the screen, but not the file.

To visualize this:

  • stdout connected to:
    • screen (terminal window)
    • and file
  • stderr connected to:
    • just the screen (terminal window)

However, there's a trick we can use. We can add 2>&1 at the end of the command for which we want to save the extra stderr output.

What 2>&1 does is tell our system to redirect stderr to stdout (because 2 represents stderr in this case, and &1 represents stdout). By doing this we essentially "mix" all messages into stdout.

We can imagine two boxes: Box A and Box B. Messages are separated. But with 2>&1 we take all messages from box B and drop them in Box A. Now that everything is in Box A (stdout), we can simply pipe to the tee command and all the output, including error messages / warnings, will be saved to the file.

So, to save both stderr and stdout messages with tee (include error messages), we can add 2>&1 at the end of the first command, like this:

sudo apt update 2>&1 | tee update.log

Now let's check the contents of the update.log file:

The WARNING line (part of stderr) is now saved into our file.

How to Append to File with the "tee" Command, Instead of Overwriting

Let's use a simple command to save the current date and time to a file:

date | tee date.log

Now let's run this command 3 times:

What will the date.log file contain?

cat date.log

Just the last output we saved, from the third command. The content from the first two is missing. Why?

Because, by default, tee will overwrite the previous content of the file.

But we can tell tee to append (add) content to the file (instead of overwriting) with the -a option. We just add it after the tee command and before the name of the file.

Here's an example of using the -a option to tell tee to append content instead of overwriting:

date | tee -a date.log

We'll see that tee kept adding the new content at the end of the date.log file. So we'll find all the output saved this time:

Hope you found this interesting.

Learn More

If you love Linux, and want to learn more about it, check out this Linux course:

Linux Foundation Certified System Administrator (LFCS) | KodeKloud
Prepare for the Linux Foundation Certified System Administrator (LFCS) Exam

It will help you learn fast about how to manage Linux systems. And you also get access to interactive labs — essentially, "Linux virtual machines" running in your browser. So you can test the commands you learn about, instantly, without having to install Linux yourself.

See you in the next blog!