VMware ESXi and vSphere Cluster Management
Split Program Output with the tee Command in Linux
Learn how Linux tee copies command output to the terminal and one or more files, including append mode, stderr capture, sudo, and pipeline errors.
The Linux tee command lets you watch command output in the terminal while saving the same data to one or more files. It is especially useful for diagnostic logs, reports, installation transcripts, and command results that you want to review later.
What the tee Command Does
tee reads data from standard input and copies it to two destinations:
- Standard output: usually the terminal, so you can see the data live.
- One or more files: so the data is retained.
Because it reads from standard input, tee is commonly placed after another command in a pipeline. A pipeline is a sequence of commands connected with the pipe operator, |.
Standard Streams and Pipelines
Linux commands normally use three standard streams:
| Stream | Name | Typical purpose |
|---|---|---|
| 0 | Standard input (stdin) | Data a command reads, often from the keyboard or another command |
| 1 | Standard output (stdout) | Normal results produced by a command |
| 2 | Standard error (stderr) | Diagnostic messages and errors |
For example, in this pipeline, ls sends its standard output into tee as standard input:
ls -l | tee output.txt
The pipe passes standard output from the command on its left to standard input for the command on its right. Ordinary use of tee captures standard output only. Standard error remains a separate stream unless you explicitly redirect it into the pipeline.
Basic tee Syntax
command | tee file
commandis the producing command.|sends that command's standard output intotee.teecopies its standard input to standard output and to the named file.fileis the destination path.
Since tee writes a copy to standard output, the command's output continues to appear in the terminal.
Save a Directory Listing
Use the following command to display a detailed directory listing and save the same listing in output.txt:
ls -l | tee output.txt
If output.txt does not exist, tee creates it. If it already exists, the default behavior is to truncate it—that is, reduce it to zero length—and write the new output. Existing contents are therefore replaced.
Append Output with -a
Use the -a option to append incoming data after the existing end of a file:
ls -l | tee -a output.txt
Append mode preserves the old contents and adds the new listing. This is useful when collecting successive command results in one report:
date | tee -a system-report.txt
uname -a | tee -a system-report.txt
df -h | tee -a system-report.txt
Without -a, each command would replace the report. Choose overwrite or append deliberately.
Write to Multiple Files
tee accepts more than one filename. The same input stream is displayed in the terminal and written to every specified file:
command | tee first.txt second.txt
To append to both files instead, use:
command | tee -a first.txt second.txt
All named files receive identical input. If one destination cannot be opened or written, tee reports the problem; check its output and exit status when reliability matters.
Capture Standard Error
Error messages may appear on screen but be absent from the file because they use standard error rather than standard output. For example, this command can produce both a valid listing and an error:
ls existing-file missing-file | tee command.log
The normal result is piped to tee, but the message about missing-file is normally sent directly to the terminal through standard error.
Merge standard error into standard output before the pipe:
ls existing-file missing-file 2>&1 | tee command.log
Here, 2>&1 redirects file descriptor 2, standard error, to file descriptor 1, standard output. Both streams then enter tee, so both are displayed and saved.
tee Options and Behaviors
| Syntax or option | Effect on file | Terminal display | Typical use |
|---|---|---|---|
tee file | Creates or overwrites file | Displays the input | Save a fresh result |
tee -a file | Creates file or appends to it | Displays the input | Add log entries or successive reports |
tee file1 file2 | Creates or overwrites both files | Displays the input | Duplicate output into two destinations |
tee -a file1 file2 | Appends to both files | Displays the input | Maintain multiple growing logs |
Hide tee's Terminal Copy
Sometimes you need tee to write a file but do not want its copied output displayed. Redirect tee's standard output to /dev/null:
command | tee output.txt > /dev/null
/dev/null is a special device that discards data written to it. This does not stop tee from writing output.txt; it only discards the copy that would otherwise reach the terminal.
Write to Protected Files with sudo tee
A common mistake is to expect sudo to grant permission to a shell redirection:
sudo printf '%s\n' 'value' > /etc/example.conf
The shell performs > /etc/example.conf before sudo runs printf. The shell is still running as your normal user, so opening the protected file can fail.
Instead, send the content through a pipeline and let elevated tee open the destination:
printf '%s\n' 'value' | sudo tee /etc/example.conf > /dev/null
In this example, printf creates the content, sudo tee writes the protected file, and the final redirection suppresses tee's terminal copy. Use sudo tee -a when appending is intended.
Output Stream Patterns
| Command pattern | What is displayed | What is saved | Notes |
|---|---|---|---|
command | tee output.txt | Standard output | Standard output | Standard error stays separate |
command 2>&1 | tee output.txt | Standard output and standard error | Both streams | Useful for diagnostic logs |
command | tee output.txt > /dev/null | Nothing from tee | Standard output | Terminal display is intentionally suppressed |
command | sudo tee protected-file > /dev/null | Nothing from tee | Standard output in the protected file | Use when elevated write permission is required |
Exit Status in Pipelines
A shell commonly reports the exit status of the last command in a pipeline. In:
command | tee output.txt
the reported status may be tee's status. If the first command fails but tee successfully receives end-of-file and writes the file, the overall pipeline can appear successful.
In shells that support it, enable pipefail:
set -o pipefail
With pipefail, the pipeline reports failure when a command in the pipeline fails, rather than hiding every earlier failure behind a successful final command.
In Bash, PIPESTATUS contains the individual statuses from the most recently executed pipeline. Inspect it immediately because another command can replace its contents:
command | tee output.txt
echo "${PIPESTATUS[@]}"
The values are listed in pipeline order: the first value belongs to command, and the second belongs to tee.
Safe File Handling
- Use
tee -awhen preserving existing content is required. - Use plain
tee fileonly when replacing the destination is intentional. - Inspect the destination path before running the command, especially when using absolute paths or
sudo. - Check that the directory exists and that you have suitable write permissions.
- Remember that overwrite mode does not preserve a prior version of the file.
- Large output can consume substantial disk space, and a full disk or write error can prevent a complete log.
Troubleshooting tee
The destination file was replaced unexpectedly
Plain tee overwrites existing files by default. Use tee -a to add output without replacing the old content.
Errors appear on screen but are missing from the file
Only standard output was probably piped into tee. Merge standard error before the pipe:
command 2>&1 | tee command.log
sudo does not fix a protected-file error
The shell likely attempted redirection before sudo ran the producing command. Pipe the content into sudo tee instead:
command | sudo tee /path/to/protected-file
The output no longer appears in the terminal
Look for a final redirection such as > /dev/null. Remove it when you need the live terminal copy.
tee reports permission denied
The current user cannot create or modify the destination or its directory. Choose a writable path, correct ownership or permissions when appropriate, or use sudo tee only when privileged access is justified.
The first command failed but the pipeline looks successful
The shell may have reported tee's successful status. Enable set -o pipefail, or inspect Bash's PIPESTATUS immediately after the pipeline.
Practical Command Logging
For a live diagnostic transcript, merge both output streams and append to a report:
diagnostic-command 2>&1 | tee -a diagnostic.log
This keeps progress visible while preserving the transcript. For a new report, omit -a; for repeated runs where earlier results matter, keep -a and consider adding a timestamp before each section.
The central pattern is simple: command | tee file displays standard output and saves it at the same time. Add -a to preserve old file contents, add 2>&1 to capture errors, provide multiple filenames to duplicate the data, and use sudo tee when the destination itself requires elevated write permission.
See also: Split the output of a program.