How to Capture Both STDERR and STDOUT to a File Using tee in Linux/Unix Shell


2 views

When working with shell commands, it's crucial to understand how file descriptors work. By default:

  • STDOUT (Standard Output) uses file descriptor 1
  • STDERR (Standard Error) uses file descriptor 2
# Basic redirection example
command > output.txt 2>&1

The tee command is particularly useful when you want to both see output in the terminal and save it to a file simultaneously. It reads from standard input and writes to both standard output and files.

# Simple tee usage
command | tee output.txt

To properly capture both streams with tee, you need to merge STDERR into STDOUT before piping to tee:

# Correct method
command 2>&1 | tee output.txt

The incorrect approach would be:

# This won't capture STDERR in the file
command | tee output.txt 2>&1

Here are some real-world scenarios where this technique is useful:

# Example 1: Compiling software
make 2>&1 | tee build.log

# Example 2: System administration
apt-get install package 2>&1 | tee install.log

# Example 3: Script debugging
./myscript.sh 2>&1 | tee debug_output.txt

For more control over the output streams:

# Send combined output to file AND stderr to separate file
command 2>&1 | tee combined.log 2>errors.log

# Append to existing files
command 2>&1 | tee -a existing.log

The left-to-right processing of redirections in shell explains why 2>&1 must come before the pipe:

  1. First, merge stderr into stdout (2>&1)
  2. Then pipe the combined stream to tee

Reversing the order would mean tee only gets the original stdout, not the merged streams.

If you're not seeing expected results:

  • Verify file permissions on the output file
  • Check if any commands are buffering their output
  • Test with simple commands first (e.g., ls or echo)

When working with Unix/Linux commands, developers often need to capture both standard output (STDOUT) and standard error (STDERR) streams simultaneously. While simple redirection (command > file 2>&1) works for direct file output, piping through tee introduces complexity in the ordering of redirections.

Consider this common mistake:

find . | tee output.txt 2>&1

This fails because:
1. STDERR (fd 2) still points to the terminal
2. Only STDOUT gets piped to tee
3. The 2>&1 applies to tee's output, not the original command

The correct syntax merges streams before piping:

find . 2>&1 | tee output.txt

This works because:
1. 2>&1 merges STDERR into STDOUT
2. The combined stream is then piped to tee
3. Both streams appear in the file and terminal

For complex commands with multiple subcommands:

(make build 2>&1; make test 2>&1) | tee build.log

When needing timestamped logging:

find /etc 2>&1 | tee -a "$(date +%Y%m%d)_system_search.log"

To separate streams while still viewing both:

command 2>&1 > >(tee stdout.log) 2> >(tee stderr.log >&2)

For process substitution in bash:

find / 2>&1 | tee >(grep -v "Permission denied" > clean.log)

Remember that:
- Redirection order matters critically
- Pipes only handle STDOUT by default
- Some programs may buffer output differently when piped
- The merged stream loses distinction between error and normal output