A Few Examples of Using the Tee Command
Tee lets you read from stdin and write to both stdout and a file at the same time. It optionally supports appending to a file.
Prefer video? There’s a video version of this blog post on YouTube that goes into a bit more detail than what’s written below.
This may help visualize what’s happening:
stdin --> tee --> stdout
|
V
file
stdin
: A command’s output is sent as input totee
tee
: Takes that output and sends it to bothstdout
and afile
stdout
: Write tee’s output to stdout (the command that producedstdin
totee
)file
: Write tee’s output to a file
# A Few Examples
Here’s a few basic examples of using tee
to start things off.
Write to both stdout and a new file:
$ echo "hello world" | tee message.txt
hello world
# The above command produced this file.
$ cat message.txt
hello world
Write to both stdout and append to a file:
$ echo "hello world" | tee -a message.txt
hello world
# The above command appended to the existing file due to the `-a` flag.
$ cat message.text
hello world
hello world
This will create a new file if it doesn’t exist just like echo "hello world" >> message.txt
.
Write to both stdout and multiple files:
$ echo "hello world" | tee a b c
hello world
# The above command created 3 new files.
$ cat a b c
hello world
hello world
hello world
Write to both stdout and to a file owned by root with sudo
:
Once in a while you may want to write to a file owned by root
when using
sudo
.
This won’t work:
# This doesn't work because the redirect doesn't happen as the root user.
$ sudo echo "hmm" > /etc/example.conf
zsh: permission denied: /etc/example.conf
This will work:
echo "yay" | sudo tee /etc/example.conf
# Let's check out the file (yep it exists and it's owned by root):
$ stat /etc/example.conf
File: /etc/example.conf
Size: 4 Blocks: 8 IO Block: 4096 regular file
Device: 820h/2080d Inode: 345077 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-12-24 10:33:38.816916746 -0500
Modify: 2022-12-24 10:33:38.816916746 -0500
Change: 2022-12-24 10:33:38.816916746 -0500
Birth: 2022-12-24 10:33:38.816916746 -0500
This is handy if you’re using sed
or other tools to perform a find / replace
in a config file.
The same as above except don’t write to stdout:
Maybe you don’t want to print the output to stdout but still want the file written.
You can do that by running: echo "yay" | sudo tee /etc/example.conf > /dev/null
# Real World Use Cases
I’ve used the sudo tee
combo a lot in the past but another use case came up
recently where I wanted to write the results of a shell script to stdout and
also copy the output to my clipboard at the same time.
The condensed version was I ended up with echo "${A_REALLY_LONG_QUERY}" | tee pbcopy
, this let me see the query’s output in the terminal and set up my
clipboard so I could paste it into another GUI tool.
pbcopy / pbpaste are macOS command line tools for interacting with the clipboard. By the way, I didn’t switch to using a Mac. This is for a client where I’m using a company issued laptop.
The same can be achieved on Linux with xclip
or a comparable tool by running echo "sweet" | tee >(xclip)
if your shell supports process substitution such as bash or zsh.
There’s a couple of ways that could have been solved but tee
felt like the
perfect tool because echoing the query AND copying it to my clipboard was my
primary goal.
In this script’s case I didn’t care about portability. It takes what’s in my
clipboard as input, processes the data in a shell script and then updates my
clipboard so I can quickly paste it into a GUI tool. I want to run ./myscript
and be done with it.
This is why I love the command line and programming in general. The shell
script and an Excel VLOOKUP()
converted a 30 minute daily workflow into about
a 3 minute task while removing lots of chances where human error could have
crept into the process.
Using tee
didn’t save a lot of time on its own but it was a piece of the
puzzle to provide an elegant solution.
The script itself took 10 minutes to write. This was one of the few cases where a time investment up front to semi-automate something ended up being very much worth it!
# Demo Video
Timestamps
- 0:06 – How tee works
- 0:24 – Echoing something to stdout and a file
- 1:03 – Appending to a file
- 1:42 – Writing to multiple files at once
- 2:17 – Using sudo tee to redirect output to a file owned by root
- 4:08 – Writing to stdout and the clipboard
What was the last problem you solved with tee? Let me know below.