Tee Command In Linux With Examples

6 min read

The tee command in Linux is a fundamental utility that solves a common dilemma for system administrators and developers: how to save command output to a file while simultaneously viewing it on the terminal. Named after the T-splitter used in plumbing, this tool reads from standard input and writes to both standard output and one or more files. Mastering tee transforms workflow efficiency, allowing for real-time monitoring of logs, debugging scripts, and creating permanent records of ephemeral terminal sessions without interrupting the data stream.

Understanding the Core Syntax and Options

Before diving into practical scenarios, Grasp the basic structure of the command — this one isn't optional. The general syntax follows the pattern tee [OPTION]... [FILE].... Unlike redirection operators such as > or >>, which sever the visual connection to the data, tee duplicates the stream.

Here are the most frequently used flags that modify its behavior:

  • -a or --append: Appends output to the specified files rather than overwriting them. This is critical for logging processes that run continuously.
  • -i or --ignore-interrupts: Ignores interrupt signals (like Ctrl+C). This ensures the file write completes cleanly even if the user terminates the command prematurely.
  • -p: Diagnoses errors writing to non-pipes immediately. The default behavior handles pipes differently, but this flag forces consistent error reporting.
  • --output-error[=MODE]: Sets behavior on write error. Modes include warn (default), warn-nopipe, exit, and exit-nopipe.

Understanding these options allows users to tailor the command for robustness in production scripts versus quick interactive debugging.

Basic Usage: The Standard Split

The most elementary use case involves piping the output of a command directly into tee followed by a filename. Consider a scenario where you are updating a package list and want to keep a record of the transaction while watching the progress Nothing fancy..

sudo apt update | tee update_log.txt

In this example, the standard output of apt update flows into tee. The command writes the text to update_log.Now, txt and simultaneously pushes it to the terminal screen. That's why if update_log. txt already exists, it is truncated (emptied) before writing begins. This behavior mirrors the > redirection operator but with the added benefit of visibility.

To verify the file contents afterward, simply run cat update_log.txt. You will see an exact replica of what scrolled across your screen Worth keeping that in mind..

Appending Data: Building Continuous Logs

Overwriting logs is rarely desirable for long-running services or scheduled cron jobs. The -a (append) flag changes the file mode from truncate to append. This is the standard pattern for daemon logging or build processes where historical context matters Most people skip this — try not to. Simple as that..

./build_script.sh | tee -a build_history.log

Every time this command executes, new output is added to the end of build_history.Practically speaking, log. The previous logs remain untouched. This approach is significantly safer than >> redirection because if the script crashes or hangs, you see exactly where it stopped in real-time, rather than discovering a truncated or empty log file after the fact.

Writing to Multiple Files Simultaneously

A powerful but often overlooked feature of tee is its ability to write to multiple files in a single pass. By providing multiple filenames as arguments, the input stream is cloned for each target. This is useful for creating redundant backups or categorizing output for different teams Most people skip this — try not to..

dmesg | tee kernel_log.txt /var/log/custom_dmesg.log backup/kernel_$(date +%F).log

Here, the kernel ring buffer output is saved to three distinct locations: a local project file, a system log directory (assuming permissions allow), and a dated backup folder. This eliminates the need for chained cp or cat commands, reducing I/O overhead and race conditions.

Handling Standard Error (stderr)

By default, tee only captures standard output (stdout). Error messages sent to standard error (stderr) will still print to the terminal but will not be saved to the file. This frequently leads to incomplete logs where the error that caused a failure is missing from the record Small thing, real impact..

To capture both streams, you must redirect stderr to stdout before piping to tee. The syntax 2>&1 merges the streams Most people skip this — try not to..

./configure 2>&1 | tee configure_log.txt

Now, both the configuration checks (stdout) and any compiler warnings or missing dependency errors (stderr) are preserved in configure_log.And txt and displayed on screen. This leads to /configure |& tee configure_log. That said, for Bash users, the shorthand |& achieves the same result: . txt And that's really what it comes down to..

Elevating Privileges: Writing to Root-Owned Files

A classic frustration occurs when a user tries to write to a protected location like /etc/ or /var/log/ using sudo with redirection:

# This FAILS: "Permission denied"
sudo echo "new config" > /etc/myconfig.conf

The shell performs the redirection before sudo executes, meaning the file is opened by the unprivileged user. tee solves this elegantly because the file is opened by the tee process itself, which runs with elevated privileges.

echo "new config" | sudo tee /etc/myconfig.conf

Here, echo runs as the standard user, but tee runs as root via sudo. The file is created and written successfully. To suppress the terminal output in this specific administrative context (since you usually just want the file written), redirect tee's stdout to /dev/null:

echo "new config" | sudo tee /etc/myconfig.conf > /dev/null

Advanced Pipeline Integration: Process Substitution

For complex workflows, tee combines powerfully with process substitution (>(...In practice, )). This allows the output stream to be fed into other commands as if they were files, enabling parallel processing of a single data source.

Imagine you need to compress a large database dump, calculate its checksum, and save the raw file simultaneously.

mysqldump large_db | tee >(gzip > dump.sql.gz) >(sha256sum > dump.sha256) > dump.sql

In this single line:

  1. In real terms, the first process substitution >(gzip > dump. 3. mysqldumpstreams data. Day to day, the second>(sha256sum > dump. In practice, gz) compresses the stream on the fly. sql.Which means sql. 4. 2. tee writes the raw stream to dump.sha256) calculates the hash concurrently.

This avoids reading the disk multiple times or creating temporary intermediate files, maximizing throughput on I/O bound systems The details matter here..

Using tee with sudo for Script Debugging

When debugging scripts that require root privileges, inserting tee at strategic points acts as a "tap" on the pipeline. You can inspect variable states or intermediate file contents without stopping the script execution or modifying the script logic heavily.

# Inside a script running as root
generate_report | tee /tmp/debug_report_stage1.txt | format_output | tee /tmp/debug_report_stage2.txt

This technique is invaluable for auditing data transformation pipelines where data fidelity must be verified at each stage.

Ignoring Interrupts for Critical Operations

When writing to network mounts or slow storage, an accidental Ctrl+C can leave a file in a corrupted or incomplete state. That's why the -i flag prevents tee from terminating immediately upon receiving a SIGINT. It finishes writing the current buffer to the file before exiting.

rsync -avz /source/ remote:/dest/ | tee -i rsync_backup.log

If the network hiccups and you hit `Ctrl

Newly Live

New Stories

Similar Ground

If This Caught Your Eye

Thank you for reading about Tee Command In Linux With Examples. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home