tee
| Since: | All Linux | |
|---|---|---|
| macOS(2001 Cheetah) | ||
| Bash 1.0(1989) |
tee reads from standard input and writes to both standard output and one or more files simultaneously. The name comes from the T-shaped pipe fitting. It is useful when you want to save a build log to a file while still seeing the output in the terminal.
Syntax
command | tee [options] [file...]
Options
| Option | Description |
|---|---|
| tee file | Writes standard input to a file and also passes it to standard output. |
| tee -a file | Appends to a file instead of overwriting it. |
| tee file1 file2 | Writes to multiple files at the same time. |
| tee /dev/null | Passes data through to standard output only, effectively the same as cat. |
Sample Code
The following examples demonstrate how tee works. Think of tee as a T-shaped pipe fitting that splits the data stream in two directions.
sample_tee.sh
# Data flow: # command output → tee → saved to file # └→ standard output (to next command)
Writes standard input to a file while also passing it to standard output.
echo "Hello" | tee output.txt Hello cat output.txt Hello
Displays build output in the terminal while saving it to a log file. Using 2>&1 includes standard error as well.
make 2>&1 | tee build.log
The -a flag appends to the file instead of overwriting it. This example appends to a log file while filtering for only errors and warnings.
make 2>&1 | tee -a build.log | grep -E "error|warning"
Writes to multiple files at the same time.
echo "test data" | tee file1.txt file2.txt file3.txt test data
Use sudo tee to write to a file that requires root privileges. sudo echo > /etc/hosts fails because the shell runs the redirect outside of sudo's permissions, but piping through sudo tee writes the file correctly.
echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hosts 127.0.0.1 myapp.local
Saves an intermediate result to a file mid-pipeline so you can inspect it later.
cat access.log | tee /tmp/debug.log | grep "ERROR" | wc -l 3
Inside a script, log timestamped output to a file while still displaying it in the terminal.
deploy.sh
LOG_FILE="/var/log/deploy_$(date +%Y%m%d).log"
run_step() {
echo "[$(date '+%H:%M:%S')] $1"
}
run_step "Running git pull..." | tee -a "$LOG_FILE"
git pull origin main 2>&1 | tee -a "$LOG_FILE"
run_step "Running npm install..." | tee -a "$LOG_FILE"
npm install 2>&1 | tee -a "$LOG_FILE"
run_step "Done" | tee -a "$LOG_FILE"
Combine with process substitution (>(...)) to stream all output to the terminal while writing only errors and warnings to a separate file.
make 2>&1 | tee >(grep -E "error|warning" > errors.log) > build.log
Use tee /dev/stderr to copy data to standard error mid-pipeline. Useful when you want to inspect a value at an intermediate step while letting the pipeline continue.
echo "target data" | tee /dev/stderr | wc -c target data 12
Common Mistakes
Common Mistake 1: tee without -a overwrites the log file each time
By default, tee overwrites the file. When recording incremental logs in a script, always use -a to append.
echo "step 1 done" | tee deploy.log echo "step 2 done" | tee deploy.log
Run the following command:
cat deploy.log step 2 done (step 1 is gone — tee overwrote the file)
Use tee -a to append to the file instead.
echo "step 1 done" | tee -a deploy.log echo "step 2 done" | tee -a deploy.log cat deploy.log step 1 done step 2 done
Common Mistake 2: sudo echo cannot write to a root-owned file
The shell handles the redirect before sudo runs, so the redirect itself is executed without root privileges. This causes a "permission denied" error.
sudo echo "127.0.0.1 myapp.local" > /etc/hosts bash: /etc/hosts: Permission denied
Pipe to sudo tee instead. The elevated privilege covers the write operation.
echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hosts 127.0.0.1 myapp.local
Notes
The sudo tee pattern is a common idiom for writing to files that require root privileges. sudo echo "..." > /etc/hosts fails because the shell executes the redirect without sudo's elevated permissions, but using sudo tee via a pipe writes the file correctly.
For more on pipes, see Pipe (|). For more on redirection, see Output Redirection (>).
If you find any errors or copyright issues, please contact us.