The tee command is one of those hidden gems in the Linux toolbox that significantly enhances productivity for system administrators, developers, and power users alike. Unlike simple redirection operators, tee offers a unique capability to split command output in two directions simultaneously—displaying results on your screen while also saving them to one or more files. This T-shaped behavior is actually where the command gets its name, functioning similarly to a T-shaped pipe fitting in plumbing that divides flow in multiple directions.
In this comprehensive guide, we’ll explore everything from basic usage to advanced techniques, equipping you with the knowledge to leverage tee effectively in your Linux workflow.
Understanding the Tee Command
Before diving into examples and practical applications, let’s establish a solid understanding of what the tee command is and why it’s so valuable in Linux environments.
What is the Tee Command?
The tee command is a standard utility in Linux and Unix-like operating systems that reads from standard input (stdin) and writes the data to both standard output (stdout) and one or more files simultaneously. This dual-output functionality is what makes tee particularly useful—it bridges the gap between viewing command output immediately and preserving that output for later reference or analysis.
In its simplest form, tee acts like a T-junction in plumbing, where data flows in from one direction and is split into two separate streams. One stream goes to your terminal display, while the other is directed to a file or multiple files.
Why Use the Tee Command?
The true value of the tee command becomes apparent in several scenarios:
- Command Logging: When executing commands with important output, tee allows you to both see the results immediately and save them for documentation.
- Debugging: When troubleshooting scripts or applications, tee helps capture output while still monitoring it in real-time.
- System Administration: When modifying configuration files that require elevated privileges, tee provides a straightforward method to write to these files when combined with sudo.
- Data Processing: When building complex command pipelines, tee enables you to save intermediate results without breaking the flow of data processing.
Unlike standard redirection operators (> or >>), which send output only to a file, tee maintains the visibility of command output on your screen while simultaneously saving it. This immediate feedback is invaluable when working with critical system commands where seeing results in real-time is essential.
Tee Command Syntax and Options
Understanding the correct syntax and available options will help you get the most out of the tee command.
Basic Syntax
The standard syntax for the tee command follows this structure:
[command] | tee [options] [filename]
Here’s what each component represents:
[command]
: The command whose output you want to capture|
: The pipe operator that sends output from the command to teetee
: The tee command itself[options]
: Optional flags that modify tee’s behavior[filename]
: One or more files where you want to save the output
For example, to display your system’s disk usage while saving it to a file:
df -h | tee disk_usage.txt
This command shows disk usage information on your screen and saves the same data to a file named disk_usage.txt.
Common Options
The tee command supports several options that extend its functionality:
-a, --append
: Appends output to the specified file(s) instead of overwriting them. This is especially useful when you want to add new data to existing logs or records.-i, --ignore-interrupts
: Ignores interrupt signals, ensuring tee completes writing operations even if the connected command is interrupted.-p, --output-error[=MODE]
: Sets specific behaviors for write errors, with various modes available:warn
: Diagnoses errors when writing outputwarn-nopipe
: Diagnoses errors only when writing to non-pipe outputsexit
: Exits on errorexit-nopipe
: Exits on error only when writing to non-pipe outputs
--help
: Displays the help manual with all available options.--version
: Shows the command version information.
To see all available options for tee on your system, simply run:
tee --help
Basic Examples of the Tee Command
Let’s explore some fundamental ways to use the tee command in everyday Linux tasks.
Displaying and Saving Command Output
One of the most common uses of tee is to view command output while simultaneously storing it in a file:
ls -l | tee file_list.txt
This command lists all files in the current directory with detailed information, displaying the results on your terminal while also saving them to file_list.txt.
For system monitoring, you can capture performance statistics:
top -b -n 1 | tee system_performance.txt
This runs the top command once in batch mode and saves the output to a file while also showing it on screen—perfect for quick system checks that need documentation.
Writing to Multiple Files
Tee can write the same output to multiple files simultaneously, which is useful for creating duplicate logs or distributing information:
echo "Important system notice" | tee notice1.txt notice2.txt notice3.txt
This command writes the message to three different files while also displaying it on your terminal.
Another practical example is creating identical configuration backups:
cat /etc/ssh/sshd_config | tee sshd_backup_$(date +%Y%m%d).txt sshd_backup_latest.txt
This creates two copies of your SSH configuration—one with today’s date and another as the “latest” version.
Appending to Existing Files
By default, tee overwrites the destination file. To append content instead, use the -a option:
echo "New log entry at $(date)" | tee -a system_log.txt
This adds a timestamped entry to system_log.txt without erasing previous content—ideal for ongoing logs or records.
You can verify the append operation worked correctly by examining the file:
cat system_log.txt
This approach is particularly valuable when building logs incrementally or adding new information to existing documentation.
Advanced Tee Command Usage
Once you’ve mastered the basics, you can leverage tee for more sophisticated operations.
Combining Tee with Other Commands
Tee excels in complex command pipelines, allowing you to capture intermediate results:
grep -r "error" /var/log/ | tee error_findings.txt | wc -l
This command searches recursively for “error” in log files, saves all matching lines to error_findings.txt, and then counts the number of errors found.
Another useful example is filtering and preserving specific information:
cat logfile.txt | grep "ERROR" | tee error-log.txt | grep "Critical" > critical-errors.txt
Here, you extract all error messages from a log, save them to error-log.txt, and then further filter for critical errors into a separate file.
Using Tee with sudo
One of tee’s most powerful applications is modifying system files that require elevated privileges:
echo "nameserver 8.8.8.8" | sudo tee -a /etc/resolv.conf
This appends Google’s DNS server to your system’s resolver configuration file. Unlike direct redirection with sudo (which would fail), this approach properly handles the permission elevation.
When editing configuration files, this technique prevents permission-denied errors:
echo "vm.swappiness=10" | sudo tee /etc/sysctl.d/99-swappiness.conf
This creates or overwrites a sysctl configuration file to adjust system swappiness without needing to open an editor with elevated privileges.
Practical Use Cases
The tee command shines in various real-world scenarios across system administration, development, and troubleshooting.
System Administration Tasks
For configuration management:
grep -v '^#' /etc/ssh/sshd_config | grep -v '^$' | tee ssh_active_settings.txt
This extracts only active (non-commented) settings from your SSH server configuration and saves them for review or documentation.
When applying system updates:
apt update && apt upgrade -y | tee system_update_$(date +%Y%m%d).log
This captures the entire update process output, creating a dated log file that can be referenced if issues arise later.
Debugging and Troubleshooting
When diagnosing application issues:
./troublesome_app --verbose 2>&1 | tee app_debug.log
This captures both standard output and error messages from an application into a single log file while also displaying them for immediate analysis.
For network diagnostics:
ping -c 10 example.com | tee ping_results.txt
This saves ping test results to a file while showing them in real-time, useful for documenting network conditions.
Automation and Scripting
Incorporating tee into shell scripts enhances logging capabilities:
#!/bin/bash
echo "Starting backup process at $(date)" | tee -a backup.log
rsync -avz /source/ /destination/ 2>&1 | tee -a backup.log
echo "Backup completed at $(date)" | tee -a backup.log
This script logs the start time, captures all rsync output (including errors), and logs the completion time to create a comprehensive record of the backup process.
For scheduled tasks:
crontab -l | tee crontab_backup.txt
This backs up your current cron jobs before making changes, ensuring you have a reference point if something goes wrong.
Comparing Tee with Similar Commands
Understanding how tee differs from other output-handling methods helps you choose the right tool for each task.
Tee vs. Simple Redirection (> and >>)
While redirection operators (> for overwrite, >> for append) also save command output to files, they don’t display that output on screen:
# Using redirection - output only goes to file
ls -la > file_list.txt
# Using tee - output goes to both screen and file
ls -la | tee file_list.txt
Tee provides immediate feedback along with storage, making it superior for interactive use and situations where you need visual confirmation.
Additionally, tee can write to multiple destinations simultaneously, which isn’t possible with basic redirection:
# This requires multiple commands with redirection
ls -la > file1.txt
cat file1.txt > file2.txt
# With tee, it's a single operation
ls -la | tee file1.txt file2.txt
The immediate dual-output capability makes tee invaluable when working with critical commands where seeing results in real-time is essential.
Tee vs. Sponge
The sponge command (from the moreutils package) reads all input before writing anything, which allows piping to the same file you’re reading from:
# This would fail with tee (truncates the file before reading)
cat file.txt | tee file.txt
# This works with sponge
cat file.txt | grep "important" | sponge file.txt
While tee writes data as it comes in, sponge buffers everything first. This makes sponge better for transforming files in-place but less suitable for real-time monitoring.
Advanced Techniques and Tips
These sophisticated techniques can help you maximize the utility of the tee command.
Hiding Standard Output
To save command output to a file without displaying it on screen:
command | tee output.txt > /dev/null
This redirects tee’s standard output to /dev/null (discarding it) while still writing to the specified file—useful for background processes or when you only need to preserve output for later review.
For a more complex example:
find / -name "*.log" 2>/dev/null | tee log_files.txt > /dev/null
This searches for all log files, silences error messages, saves the list to log_files.txt, and prevents display on the terminal.
Working with Binary Data
While tee primarily handles text output, it can also process binary data:
dd if=/dev/sda bs=512 count=1 | tee mbr_backup.bin | hexdump -C
This reads the Master Boot Record from a disk, saves a binary copy to mbr_backup.bin, and displays a hexadecimal representation of the data.
When working with binary files, be cautious about viewing the output directly in your terminal, as it may contain control characters that could affect terminal behavior.
Performance Considerations
For large outputs, tee’s performance can be optimized:
# Using a larger buffer size with dd
command | dd bs=1M | tee large_output.txt
This leverages dd’s buffering capabilities to improve performance when handling large data streams.
When processing gigabytes of data, consider the filesystem performance of your destination:
command | tee /tmp/ramdisk/large_output.txt
Using a RAM disk or high-performance storage for tee’s output file can prevent I/O bottlenecks during intensive operations.
Common Issues and Troubleshooting
Even with a seemingly straightforward command like tee, issues can arise. Here’s how to address them.
Permission Denied Errors
The most common issue with tee occurs when writing to protected files:
# This will fail
echo "new setting" | tee /etc/system.conf
# Permission denied
# Correct approach
echo "new setting" | sudo tee /etc/system.conf
Always remember to use sudo with tee (not before the command being piped) when writing to system files or directories that require elevated privileges.
For directories with complex permissions:
mkdir -p ~/logs
echo "Log entry" | tee ~/logs/application.log
Ensure the target directory exists and has appropriate write permissions before using tee.
Unexpected Output Behavior
When working with commands that use buffered output, you might not see results immediately:
# Buffered output may delay appearance in tee
long_running_command | tee output.log
# Force unbuffered operation
long_running_command | stdbuf -o0 tee output.log
Using stdbuf can force unbuffered operation, ensuring real-time output appears as it’s generated.
For applications with different output streams:
# Capture both stdout and stderr
command 2>&1 | tee complete_log.txt
# Separate stdout and stderr
command 2> >(tee stderr.log >&2) | tee stdout.log
The second example uses process substitution to capture standard error separately from standard output.