Tee Command

Updated on

Unix Tee

The tee command is available on all Unix systems. It takes in any number of files as arguments and copies the stdin to all these files and the stdout. This can be a very helpful command when using Unix pipes.

Multi-file Output

It can be helpful to duplicate the output of a command across multiple files. By default, shells only provide one stdout stream, so it’ll take several commands or a for-loop to write to several files.

tee provides an alternative. The command below copies the output across 3 files:

echo "something" | tee file1 | tee file2 > file3

tee can also take in multiple file name arguments, where the output is copied to all of them. The following command is equivalent to the above:

echo "something" | tee file1 file2 file3 > /dev/null

This can further be further exploited with bash for loops. The following will copy the message across 100 different files:

echo "something" | tee $(for x in {1..100}; do echo file$x; done) >/dev/null

You can similarly append to files using the -a option. This is analogous to the bash syntax >>.

The following command will append to files 1 and 3, but overwrite file 2:

echo "something" | tee -a file1 | tee file2 >> file3

Writing Stderr

Consider this C program, which will write “something” to the stderr:

#include <stdio.h>
 
int main(void) {
    fprintf(stderr, "something\n");
}

tee only reads from the stdin. To use this output with tee, we’ll need to first redirect the stderr to stdout. Suppose the C program above is compiled into an executable called a.out:

./a.out 2>&1 | tee file1 file2

Elevating Permissions

It’s common on a single-user system, like your personal computer, to need to write to files that are write-only for the root user. For example consider the following command:

sudo echo "something" > root_file

This won’t work, as the sudo only applies to echo "something" not > root_file. One alternative would be to run the entire shell as root:

sudo bash -c 'echo "something" > root_file'

But now you’ve given root access to the entire command! We only want to give root access to the “write” operation. tee can do just that!

Both of the following will use the root user to write to the file root_file, but the echo command itself will still be run by your user.

echo "something" | sudo tee root_file
echo "something" | sudo tee root_file &>/dev/null

echo isn’t a very serious application of tee, though there are many cases where we only want to elevate permissions for the write and not the whole command.

Elevating Permissions for Vim

If you open a file that’s inaccessible for writing by your user with Vim, tee can be used to switch to the root user just for writing!

The following vim command writes your current buffer to the file as the root user:

:w ! sudo tee %

To deconstruct that command a bit, we start with :w which is the write command. We use ! to invoke a shell. :w will provide the current buffer as through the stdin to the shell. We run the command sudo tee %, where Vim expands % to the current file name. tee will overwrite the file name expand from % with the stdin provided by the :w command.