The tee command in Linux has a long pedigree, being developed way back in 1973. The fact that it’s been around for so long is a testament to its usefulness. But what’s even more surprising is how little it has changed since then. Linux’s philosophy of “do one thing and do it well”, has served the tee command in good stead, as it continues to do what it was designed to with little fuss. For a command that seems to have such a specific functionality, the tee command is quite useful in a range of unexpected scenarios.
What Tee Does
The tee command takes the output from one command and splits it into multiple streams, allowing the user to send it to several destinations. The most common destination is the terminal itself, as usual. But in addition to this, tee also lets you send it simultaneously to one or more files. This way, you not only see the output of a command, but you can also store it for later use.
Normally, we get to choose between seeing the output of a command or saving that output to a file. Consider these two commands:
ls -l
and
ls -l > test.txt
Here’s how both these commands execute:

You can see that in the first case, the output is shown directly on the screen. In the second case, I’ve redirected the output to the file “test.txt”. In the second case, there is no output on the screen, and the terminal simply completes the command in the background. But we can see that the output is saved in the file when we display it with cat.
The lesson is clear. We can either show the output of the command, or we can save it to a file, but not both. With the tee command, however, we can do just that. Consider the following command:
ls -l | tee testwithtee.txt
Here’s the output:

Here, you can see that the output was displayed immediately after running the command, but the file “testwithtee.txt” was also created. This means that the output was sent to two destinations at the same time – once to the standard output, and once to a file. And this, in a nutshell, is what tee does.
But why would you want to do this? What makes tee so valuable when its purpose is seemingly so random?
Why we Use Tee
Despite its odd-sounding functionality, tee is surprisingly useful in a variety of situations. Here are some of them:
Monitor Progress and Keep a Record at the Same Time
Sometimes, you run important commands whose progress you want to monitor as it happens. At the same time, you want to keep a record of the output to refer back to in case something goes wrong and you need to debug the cause. A good example of this is the “apt upgrade” command. This command upgrades the packages on your system to their latest versions. You often want to see what’s happening as the packages are being installed, but keeping a record of the output is useful in case something breaks, and you want to have a timestamped record of which packages were updated when. For that, the following command is useful:
sudo apt upgrade | tee apt_upgrade_log_$(date +%Y%m%d_%H%M%S).txt
This command runs “apt upgrade” and pipes the output to tee, allowing us to see the output as it runs like this:

However, in addition to this, we have a new file created after the command has run:

This file contains the entire output of the recently run “apt upgrade” command. Now, if we later find a conflict in package versions, some functionality breaks, we can always go back to this time-stamped file and examine its contents to see which version was replaced and when.
Appending Output to a File
When you use tee in the way shown above, it creates a new file by default or overwrites any existing file with the same name. But sometimes you just want to add to whatever exists, instead of creating something new. Log files are a classic example, where you don’t want to remove what already exists. To do this, we just use the “-a” or “–append” flag as shown here:
command | tee -a filename.txt
Here’s a demonstration of how this works:

In this screenshot, I first create a file with tee called “testwithtee.txt”, as before. But next, I use a simple echo command with tee and the “-a” append parameter. When the command completes, you can see that the new text is appended to the bottom of the contents of the existing file as expected.
If you have a long-running series of commands and want to keep a continuous track of the output over a period of time, you can use the append command to get a continuous readout of everything that transpires, so you can go back and check a single file, while the previous section demonstrated how to create a separate file each time.
Saving Output to Multiple Files
Sometimes, we need to send output not just to one file and the terminal, but to multiple files simultaneously. The command for that is:
command | tee file1.txt file2.txt file3.txt
This might seem like a niche scenario, but it’s actually quite useful. Let’s say that, as a system administrator, you need to run a script that monitors the server’s health. We need a file that always contains the most recent, up-to-date information with the script’s latest output. At the same time, we need to create a copy in a separate location that contains files, each containing the output of the previous day’s scripts. For this, we need to run a command that writes to two separate days simultaneously. So a command like this would work:
(df -h; echo ""; free -h; echo ""; uptime) | tee current_system_status.txt /var/log/daily_reports/status_$(date +%Y%m%d_%H%M%S).txt
This command creates a “current_system_status.txt” file and also a backup in a separate location for future reference if we want to track the output over several days.
Appending and Overwriting Simultaneously with tee
In the first two examples, we saw that tee overwrites files by default, but that we can change this behavior with the “-a” append flag. Unfortunately, it’s not possible to do both of these simultaneously. So in the above example, if we want to append the current system’s status to an existing file, while overwriting the contents of a “current” file, it’s not possible using the regular functionality.
However, we can achieve this result by chaining a couple of pipes together. It’s a clever workaround demonstrating how experienced system admins can combine functionalities to achieve normally unachievable results. Consider this example:
echo "This is a test line." | tee file_to_overwrite.txt | tee -a file_to_append.txt
The first tee command overwrites the contents of “file_to_overwrite.txt”, but then, instead of allowing it to send its output to the standard output as usual, we instead pipe it to a second tee command that then uses the “-a” append flag to append the content to another file. Pretty clever, right?
Conclusion
As you can see, the tee command is quite versatile. While at first blush, it may seem as if the command’s functionality is rather niche, you can see that it has its place in a number of common situations, usually involving monitoring, debugging, and record keeping. Knowing how to use tee effectively can allow you to save a lot of time that you didn’t even know could be saved!

I’m a NameHero team member, and an expert on WordPress and web hosting. I’ve been in this industry since 2008. I’ve also developed apps on Android and have written extensive tutorials on managing Linux servers. You can contact me on my website WP-Tweaks.com!

Leave a Reply