--- title: 'Tee Command' description: 'The powerful shell-stream controller' updateDate: 'December 29 2023' --- # 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: ```bash 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: ```bash 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: ```bash 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: ```bash echo "something" | tee -a file1 | tee file2 >> file3 ``` ### Writing Stderr Consider this C program, which will write "something" to the `stderr`: ```c #include 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`: ```bash ./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: ```bash 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: ```bash 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. ```bash 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: ```vim :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.