tee — quick reference
Copy stdin to files and stdout
Read from a pipe or redirect and write the same stream to one or more files plus the terminal.
| When to use | Command |
|---|---|
| Write stdin to a file and print it on the terminal | command | tee file |
| Append instead of overwriting the file | command | tee -a file |
| Append using the long option name | command | tee --append file |
| Write the same stream to several files at once | command | tee file1 file2 |
Treat a file literally named - in the current directory |
command | tee ./- |
Signals and write errors
Control how tee reacts to interrupts and failed writes on non-pipe outputs.
| When to use | Command |
|---|---|
| Keep running when the terminal sends interrupt signals (where supported) | command | tee -i file |
| Same as above with the long name | command | tee --ignore-interrupts file |
| Diagnose write errors on regular files (not pipes) | command | tee -p file |
| Warn on any write error | command | tee --output-error=warn file |
Warn only on non-pipe write errors (default with -p on GNU builds) |
command | tee --output-error=warn-nopipe file |
| Exit immediately on any write error | command | tee --output-error=exit file |
| Exit on non-pipe write errors | command | tee --output-error=exit-nopipe file |
Help and version
| When to use | Command |
|---|---|
| Show built-in usage text | tee --help |
| Print the installed package version | tee --version |
| Short version flag (uutils build on Ubuntu 25.04) | tee -V |
tee — command syntax
tee copies standard input to each FILE and to standard output. Synopsis from tee --help on Ubuntu 25.04 (tee uutils coreutils 0.2.2):
tee [OPTION]... [FILE]...If a FILE is -, it refers to a file named - in the current directory (use ./- when you mean that path). tee does not edit system databases — it only writes bytes you pipe into it.
tee — command examples
Essential Save pipeline output and still see it on screen
Use tee when a command prints useful text but you also want a log file — for example after filtering with grep.
Run the command:
PREFIX=tcs_
WORKDIR=/tmp/${PREFIX}lab
mkdir -p "$WORKDIR" && cd "$WORKDIR"
echo -e 'num 1\nother\nnum 2' > ${PREFIX}src.txt
grep num ${PREFIX}src.txt | tee ${PREFIX}grep.txtSample output:
num 1
num 2Confirm the file holds the same lines:
cat ${PREFIX}grep.txtSample output:
num 1
num 2Without tee, redirecting with > would hide those lines from the terminal.
Essential Append to a log without wiping earlier lines
The default is overwrite. Pass -a when you are building a log file over multiple runs.
Run the command:
PREFIX=tcs_
WORKDIR=/tmp/${PREFIX}lab
mkdir -p "$WORKDIR" && cd "$WORKDIR"
echo 'first line' | tee ${PREFIX}log.txt
echo 'second line' | tee -a ${PREFIX}log.txt
cat ${PREFIX}log.txtSample output:
first line
second lineAfter cat:
first line
second lineEach append adds to the end; tee still prints the new line to the terminal once per run.
Essential Write a root-owned file from a normal user pipeline
Shell redirection runs in your shell, so echo text > /etc/example fails without root. Put sudo on tee instead.
Run the command:
PREFIX=tcs_
echo "root line" | sudo tee /tmp/${PREFIX}rootfile.txt
sudo cat /tmp/${PREFIX}rootfile.txtSample output:
root line
root lineThe same pattern works for files under /etc when you need to capture installer or diagnostic output with elevated privileges.
Common Branch a pipeline — file plus another filter
tee can sit in the middle of a pipe: one copy goes to disk, the rest of the stream continues to the next command.
Run the command:
PREFIX=tcs_
WORKDIR=/tmp/${PREFIX}lab
mkdir -p "$WORKDIR" && cd "$WORKDIR"
echo -e 'alpha\nbeta\ngamma' | tee ${PREFIX}chain.txt | grep beta
cat ${PREFIX}chain.txtSample output:
beta
cat output:
alpha
beta
gammagrep only sees beta, but ${PREFIX}chain.txt keeps the full stream.
Common Save output to a file but hide it from the terminal
Send tee's stdout to /dev/null when you only care about the file copy.
Run the command:
PREFIX=tcs_
WORKDIR=/tmp/${PREFIX}lab
mkdir -p "$WORKDIR" && cd "$WORKDIR"
echo 'hidden' | tee ${PREFIX}hidden.txt > /dev/null
cat ${PREFIX}hidden.txtSample output:
hiddenNothing prints to the terminal, but the file still contains hidden.
Common Write one stream to multiple files
List more than one path and tee duplicates the input to each file and to stdout.
Run the command:
PREFIX=tcs_
WORKDIR=/tmp/${PREFIX}lab
mkdir -p "$WORKDIR" && cd "$WORKDIR"
echo 'multi' | tee ${PREFIX}a.txt ${PREFIX}b.txt
md5sum ${PREFIX}a.txt ${PREFIX}b.txtSample output:
multi
a8f5f167f44f4964e6c998dee827110 /tmp/tcs_lab/tcs_a.txt
a8f5f167f44f4964e6c998dee827110 /tmp/tcs_lab/tcs_b.txtMatching checksums confirm both files received the same bytes.
Advanced Control behavior when a write to disk fails
On full disks or read-only mounts, tee may fail while writing to a file even though stdout still works. --output-error chooses whether to warn or exit.
Run the command:
PREFIX=tcs_
WORKDIR=/tmp/${PREFIX}lab
mkdir -p "$WORKDIR" && cd "$WORKDIR"
echo 'warn test' | tee --output-error=warn ${PREFIX}warn.txtSample output:
warn testOn GNU coreutils builds, pair -p with the default warn-nopipe mode when diagnosing permission or disk errors on regular files.
Advanced Write to a file whose name is a single dash
A bare - operand means a file named - in the current directory, not stdout.
Run the command:
PREFIX=tcs_
WORKDIR=/tmp/${PREFIX}lab
mkdir -p "$WORKDIR" && cd "$WORKDIR"
echo 'dash test' | tee ./-
ls -la ./-Sample output:
dash test
-rw-r--r-- 1 root root 10 Jul 1 14:18 ./-Use ./- so the shell does not treat - as a special operand.
tee — when to use / when not
| Use tee when | Use something else when |
|---|---|
|
|
tee vs shell redirection
| tee | > / >> |
|
|---|---|---|
| Needs a pipeline | Yes — reads stdin | No — shell opens the file |
| Shows output on terminal | Yes (unless you redirect stdout away) | No |
| Append | tee -a file |
>> file |
| Write protected paths as user | sudo tee file |
sudo sh -c 'echo x > file' or editor |
| Split stream to file and another command | Natural fit | Requires process substitution or temp files |
Use tee when the data is already flowing through a pipe. Use > or >> when you only need a file and do not care about terminal output.
Related commands
Commands that often appear in the same pipelines and logging workflows.
| Command | One line |
|---|---|
| tee | Copy stdin to files and stdout (this page) |
| sudo | Elevate tee to write protected paths |
| wget | Download to a file (no stdin copy needed) |
Browse the full index in our Linux commands reference.
tee — interview corner
What does the tee command do in Linux?
tee reads standard input and writes that data to every file you name, while also copying it to standard output. The name comes from a T-splitter in plumbing — one stream becomes many outputs.
Typical pattern:
dmesg | tee /tmp/boot.logYou see kernel messages on the terminal and save the same text to /tmp/boot.log. It is a coreutils utility and appears in almost every Linux distribution.
A strong answer is:
"tee copies stdin to one or more files and also to stdout. I use it in pipelines when I want to log output and still watch it, or when I need sudo tee to write a root-owned file from a normal user's pipe."
When would you use tee instead of > or >>?
Shell redirection (>, >>) connects a command's stdout directly to a file. The bytes never hit the terminal unless you use another tool.
tee fits when:
- Output is already in a pipe (
cmd1 | tee log | cmd2) - You want both a file and the terminal
- You need
sudo teebecause redirection runs in your shell without elevated rights
Redirection fits when you only need the file and want the simplest syntax.
A strong answer is:
"I use tee inside pipelines when I need a file copy and visible output, or sudo tee for protected paths. Plain redirection is better when I only need the file and I'm not splitting a pipe."
Why is sudo tee common for editing /etc files?
When you run echo 'config' > /etc/foo.conf, your shell opens /etc/foo.conf for writing. The shell runs as your user, so the redirect fails on root-owned files.
sudo tee runs the write with root privileges while your upstream command stays unprivileged:
echo 'config' | sudo tee /etc/foo.confSome admins add sudo tee -a to append to logs under /var/log the same way.
A strong answer is:
"Redirection is done by the shell as my user, so > /etc/file fails. sudo tee runs the write elevated while the generating command can stay unprivileged — that's the usual pattern for quick /etc updates from a pipe."
How do you append with tee without overwriting the file?
Pass -a or --append. Default tee truncates each output file before writing.
./run-tests.sh | tee -a results.logEach run adds to the end of results.log. This mirrors >> but works in the middle of a pipeline.
A strong answer is:
"tee -a appends to files instead of truncating them. I use it for build or test logs when each run should add lines without wiping earlier output."
Can tee sit in the middle of a pipeline?
Yes. tee writes its stdin to files, then passes the same data to stdout for the next stage.
journalctl -u nginx --since today | tee /tmp/nginx.log | grep error/tmp/nginx.log gets the full journal slice; grep only sees what tee forwards. That is the main reason tee exists — branching a live stream.
A strong answer is:
"Yes — tee duplicates the stream to disk and stdout, so I can log everything and still pipe a subset to grep or awk. The file gets the full stream; downstream tools get the same bytes tee prints."
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Permission denied writing the file |
File or directory not writable by your user | sudo tee path or fix ownership/mode |
| Empty file but command printed output | Wrong order — tee not in the pipe path |
Put tee where stdin carries the data: cmd | tee file |
| File truncated when you meant to append | Missing -a |
Use tee -a file |
| Nothing on terminal but file is correct | Stdout redirected away | Remove > /dev/null on tee's stdout if you want to see output |
tee: 'file': Is a directory |
Operand is a directory | Pass a file path, not a directory |
| Interrupt still stops the pipeline | -i not supported or signal hits upstream command |
Check tee --help on your build; protect the upstream command separately |
