LFCS Part 46: Mastering I/O Redirection in Linux

Learn how to control where command output goes and where input comes from using standard streams, file descriptors, and redirection operators in Linux

25 min read

Introduction

Every Linux command you run has three invisible data streams attached to it. These streams are like pipes that carry information in and out of your commands. Understanding how to control these streams is one of the most powerful skills in Linux system administration—it allows you to automate tasks, filter data, save logs, suppress errors, and build complex command pipelines.

In this comprehensive guide, you'll learn exactly how I/O (Input/Output) redirection works in Linux. We'll cover standard input, standard output, and standard error, along with all the redirection operators you need to control where data flows. By the end, you'll be able to redirect output to files, combine streams, discard unwanted messages, and build powerful command combinations.

What is I/O Redirection?

I/O redirection is the mechanism that allows you to control where a command's input comes from and where its output goes. By default:

  • Commands read input from your keyboard (standard input)
  • Commands send normal output to your terminal screen (standard output)
  • Commands send error messages to your terminal screen (standard error)

With redirection, you can change these defaults. You can:

  • Send output to a file instead of the screen
  • Read input from a file instead of the keyboard
  • Separate error messages from normal output
  • Discard unwanted output entirely
  • Combine multiple streams

This is essential for automation, logging, filtering data, and building complex command pipelines.

Understanding Standard Streams

Every process in Linux automatically has three standard streams open:

1. Standard Input (stdin) - File Descriptor 0

Standard input is where a command reads its input data. By default, this is your keyboard. When you type into a terminal, you're providing data to stdin.

File descriptor number: 0

Example: The cat command reads from stdin when no filename is provided:

cat
# Now type something and press Enter
# The command echoes what you type
# Press Ctrl-D to signal end of input

2. Standard Output (stdout) - File Descriptor 1

Standard output is where a command sends its normal, successful results. By default, this goes to your terminal screen.

File descriptor number: 1

Example: When you run ls, the list of files is sent to stdout:

ls
Desktop  Documents  Downloads  Music  Pictures

3. Standard Error (stderr) - File Descriptor 2

Standard error is where a command sends error messages and diagnostics. By default, this also goes to your terminal screen, but it's a separate stream from stdout.

File descriptor number: 2

Example: When a command encounters an error:

cat nonexistentfile.txt
cat: nonexistentfile.txt: No such file or directory

The error message above was sent to stderr, not stdout.

Why Separate stdout and stderr?

Having separate streams for normal output and errors is incredibly useful:

  1. Filter errors separately: You can save normal output to a file while still seeing errors on screen
  2. Log files clean: Error logs can be kept separate from data logs
  3. Scripting: Scripts can detect errors by checking stderr without parsing output data
  4. Automation: Automated processes can handle errors differently from normal output

File Descriptors Explained

File descriptors are numbers that the Linux kernel uses to track open files and streams. Every process has a file descriptor table:

File DescriptorNameDefault Destination
0stdinKeyboard
1stdoutTerminal screen
2stderrTerminal screen

When you use redirection, you're changing where these file descriptors point. Instead of pointing to your terminal, they can point to files, other commands, or even be closed entirely.

Redirecting Standard Output (stdout)

The most common redirection operation is sending stdout to a file instead of the screen.

The > Operator: Redirect and Overwrite

The > operator redirects stdout to a file, overwriting the file if it already exists.

Syntax:

command > filename

Example: Save directory listing to a file:

ls > filelist.txt

What happens:

  1. The ls command runs and generates output
  2. Instead of displaying on screen, output goes to filelist.txt
  3. If filelist.txt already exists, its contents are completely replaced
  4. If the file doesn't exist, it's created

View the contents:

cat filelist.txt
Desktop
Documents
Downloads
Music
Pictures

Another example: Save current date and time:

date > timestamp.txt
cat timestamp.txt
Mon Dec 11 14:32:15 EST 2025

The >> Operator: Redirect and Append

The >> operator redirects stdout to a file, appending to the file if it already exists.

Syntax:

command >> filename

Example: Add multiple entries to a log file:

echo "System check started" > system.log
echo "Checking disk space..." >> system.log
df -h >> system.log
echo "Check completed" >> system.log

cat system.log
System check started
Checking disk space...
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   20G   28G  42% /
Check completed

Notice:

  • First command uses > to create/overwrite the file
  • Subsequent commands use >> to add to the file
  • Each append adds to the end without removing previous content

Practical stdout Redirection Examples

Save command output for later review:

ps aux > running_processes.txt
netstat -tuln > network_connections.txt

Create a file with specific content:

echo "127.0.0.1 localhost" > /etc/hosts.backup

Capture system information:

uname -a > system_info.txt
lscpu >> system_info.txt
free -h >> system_info.txt

Redirecting Standard Input (stdin)

Instead of typing input manually or reading from keyboard, you can redirect stdin to read from a file.

The < Operator: Redirect Input

The < operator tells a command to read its input from a file instead of the keyboard.

Syntax:

command < filename

Example: Sort the contents of a file:

First, create a file with unsorted data:

cat > names.txt
Zoe
Alice
Mike
Bob
# Press Ctrl-D to finish

Now sort it using input redirection:

sort < names.txt
Alice
Bob
Mike
Zoe

What happened:

  1. sort normally reads from keyboard (stdin)
  2. With <, we redirected stdin to read from names.txt
  3. sort processed the file contents and sent output to stdout (screen)

Combining Input and Output Redirection

You can redirect both input and output in the same command:

Example: Sort a file and save the result:

sort < names.txt > sorted_names.txt
cat sorted_names.txt
Alice
Bob
Mike
Zoe

What happened:

  1. Input (<) came from names.txt
  2. The sort command processed it
  3. Output (>) went to sorted_names.txt

Another example with /etc/services:

# Get the first 10 lines of sorted /etc/services
sort < /etc/services | head

# Output (sorted alphabetically):



acap            674/tcp                 # ACAP
acap            674/udp                 # ACAP

Redirecting Standard Error (stderr)

Error messages go to stderr (file descriptor 2), not stdout (file descriptor 1). To redirect errors, you must specify the file descriptor.

The 2> Operator: Redirect Errors

The 2> operator redirects stderr to a file.

Syntax:

command 2> error_file

Example: Try to list a directory that doesn't exist:

Without redirection:

ls /nonexistent
ls: cannot access '/nonexistent': No such file or directory

The error appears on screen. Now redirect it:

ls /nonexistent 2> errors.txt

Nothing appears on screen! The error went to the file:

cat errors.txt
ls: cannot access '/nonexistent': No such file or directory

Why 2> and Not Just >?

The number before > specifies which file descriptor to redirect:

  • > is shorthand for 1> (redirect stdout)
  • 2> redirects stderr
  • 0< redirects stdin (though < alone works)

Example showing the difference:

# Create a scenario with both output and errors
ls /home /nonexistent

# Output shows both:
ls: cannot access '/nonexistent': No such file or directory
/home:
centos9  user1  user2

Now redirect only stdout:

ls /home /nonexistent > output.txt
ls: cannot access '/nonexistent': No such file or directory

cat output.txt
/home:
centos9  user1  user2

Notice: The error still appeared on screen because we only redirected stdout (>), not stderr.

Now redirect only stderr:

ls /home /nonexistent 2> errors.txt
/home:
centos9  user1  user2

cat errors.txt
ls: cannot access '/nonexistent': No such file or directory

Notice: Normal output appeared on screen, but errors went to the file.

Redirecting Both stdout and stderr to Different Files

You can redirect stdout and stderr to separate files in one command:

Syntax:

command > output.txt 2> errors.txt

Example:

ls /home /nonexistent /tmp > output.txt 2> errors.txt

cat output.txt
/home:
centos9  user1  user2
/tmp:
file1.txt  file2.txt

cat errors.txt
ls: cannot access '/nonexistent': No such file or directory

This is extremely useful for logging:

  • Normal operation logs go to one file
  • Error logs go to another file
  • Easy to monitor problems separately

Redirecting Both stdout and stderr Together

Sometimes you want all output (both normal and errors) in the same file.

The &> Operator: Redirect Both Streams

The &> operator redirects both stdout and stderr to the same file.

Syntax:

command &> output_file

Example:

grep root /etc/* &> search_results.txt

What this does:

  1. grep searches all files in /etc/ for "root"
  2. Normal matches go to stdout
  3. "Permission denied" and "Is a directory" errors go to stderr
  4. Both streams are captured in search_results.txt

View the file:

cat search_results.txt | head
grep: /etc/audit: Permission denied
/etc/aliases:postmaster:	root
/etc/aliases:bin:		root
grep: /etc/alternatives: Is a directory
/etc/anacrontab:MAILTO=root
/etc/group:root:x:0:

You can see both errors and matches mixed together in the output.

The 2>&1 Syntax: Redirect stderr to stdout

An alternative (older) syntax for redirecting both streams:

Syntax:

command > output_file 2>&1

This means:

  1. > output_file - redirect stdout to output_file
  2. 2>&1 - redirect stderr (file descriptor 2) to wherever stdout (file descriptor 1) is currently going

Example:

grep root /etc/* > search_results.txt 2>&1

This achieves the same result as &>, but the order matters:

Correct order:

command > file 2>&1  # ✓ Works: stdout goes to file, then stderr follows

Wrong order:

command 2>&1 > file  # ✗ Doesn't work as expected

Why? Because 2>&1 redirects stderr to wherever stdout is currently pointing. If stdout hasn't been redirected yet, stderr goes to the terminal.

Modern recommendation: Use &> instead—it's clearer and less error-prone.

Discarding Output with /dev/null

/dev/null is a special file in Linux that discards everything written to it. It's called the "null device" or "black hole."

Location: /dev/null

Purpose: Throw away output you don't want to see or save

Suppressing Errors with 2>/dev/null

One of the most common uses is suppressing error messages.

Example: Find files named "hosts" without seeing permission errors:

Without redirection:

find / -name "hosts"
find: '/etc/polkit-1/rules.d': Permission denied
find: '/etc/audit': Permission denied
/etc/hosts
find: '/root': Permission denied
/etc/avahi/hosts
find: '/var/lib/sss/db': Permission denied

Many permission errors clutter the output! Redirect them:

find / -name "hosts" 2>/dev/null
/etc/hosts
/etc/avahi/hosts
/usr/share/doc/python3-dns/examples/hosts

Much cleaner! Only actual results are shown.

What happened:

  1. find generates normal output (file paths found) → stdout → terminal
  2. find generates errors (permission denied) → stderr → /dev/null (discarded)
  3. You only see what you care about

Suppressing All Output with &>/dev/null

To completely silence a command (both stdout and stderr):

Syntax:

command &>/dev/null

Example: Run a command silently:

grep root /etc/* &>/dev/null

Nothing appears! All output (matches and errors) was discarded.

Use case: This is useful in scripts when you only care about the command's exit status, not its output:

if grep -q "error" /var/log/syslog &>/dev/null; then
    echo "Errors found in syslog!"
fi

Suppressing Only Normal Output

You can also suppress stdout while keeping stderr visible:

Syntax:

command >/dev/null

Example:

ls /home /nonexistent >/dev/null
ls: cannot access '/nonexistent': No such file or directory

Only the error is shown; normal output was discarded.

Real-World I/O Redirection Scenarios

Scenario 1: Creating a System Report

Generate a comprehensive system report:

{
    echo "========================================="
    echo "System Report - $(date)"
    echo "========================================="
    echo
    echo "Hostname:"
    hostname
    echo
    echo "Kernel Version:"
    uname -r
    echo
    echo "Uptime:"
    uptime
    echo
    echo "Disk Usage:"
    df -h
    echo
    echo "Memory Usage:"
    free -h
    echo
    echo "Top 10 Processes by Memory:"
    ps aux --sort=-%mem | head -11
} > system_report.txt

The curly braces {} group all commands together, and their combined output goes to the file.

Scenario 2: Cleaning Log Output

Search logs but filter out noise:

# Search for errors in syslog, but exclude permission denied messages
grep -i error /var/log/syslog 2>/dev/null | grep -v "permission denied"

Scenario 3: Automated Backup with Logging

Create a backup script that logs both successes and errors:

#!/bin/bash
DATE=$(date +%Y-%m-%d)
LOGFILE="/var/log/backup_${DATE}.log"

{
    echo "Backup started at $(date)"
    tar -czf /backup/home_${DATE}.tar.gz /home
    echo "Backup completed at $(date)"
} >> $LOGFILE 2>&1

This appends all output (normal and errors) to the log file.

Scenario 4: Testing Configuration Files

Test if a configuration file has syntax errors:

# Test nginx configuration
nginx -t > /dev/null 2>&1

if [ $? -eq 0 ]; then
    echo "Configuration is valid"
else
    echo "Configuration has errors"
    nginx -t  # Show the errors
fi

Scenario 5: Creating Empty Files vs. Clearing Files

Create an empty file or clear an existing file:

# Method 1: Using redirection
> empty_file.txt

# Method 2: Using echo with redirection
echo -n > empty_file.txt

# Method 3: Clear an existing file
> /var/log/old_log.txt

The > operator with no command creates or clears a file.

Common Patterns and Idioms

Pattern 1: Save Output and Display It

Use tee (covered in next post) or redirection with cat:

ls -la > listing.txt
cat listing.txt

Pattern 2: Append Date-Stamped Log Entries

echo "$(date): Backup completed" >> /var/log/backup.log

Pattern 3: Redirect to Multiple Files

# Save to both files (using tee, covered next post)
ls -la | tee file1.txt file2.txt

# Or do it manually:
ls -la > file1.txt
ls -la > file2.txt

Pattern 4: Conditional Redirection in Scripts

if [ "$DEBUG" = "true" ]; then
    command 2>&1 | tee debug.log
else
    command &>/dev/null
fi

Visual Diagram: I/O Redirection Flow

┌─────────────────────────────────────────────────────────────────┐
│                         COMMAND                                 │
│                                                                 │
│  Input ──→ [Process] ──→ Output                                │
│   (0)                     (1)                                   │
│                      └──→ Errors                                │
│                           (2)                                   │
└─────────────────────────────────────────────────────────────────┘

DEFAULT BEHAVIOR (No Redirection):
├─ stdin  (0) ← Keyboard
├─ stdout (1) → Terminal screen
└─ stderr (2) → Terminal screen

WITH REDIRECTION:
├─ stdin  (0) ← file.txt          (using <)
├─ stdout (1) → output.txt        (using > or >>)
└─ stderr (2) → errors.txt        (using 2>)

COMBINED REDIRECTION:
├─ stdin  (0) ← input.txt         (using <)
└─ stdout + stderr → all.txt      (using &> or 2>&1)

TO /dev/null (DISCARD):
├─ stdout → /dev/null             (using >/dev/null)
├─ stderr → /dev/null             (using 2>/dev/null)
└─ both   → /dev/null             (using &>/dev/null)

Best Practices for I/O Redirection

1. Use Append (>>) for Logs

Always use >> when adding to log files to avoid accidentally deleting previous logs:

# Good
echo "Log entry" >> /var/log/app.log

# Dangerous
echo "Log entry" > /var/log/app.log  # Deletes previous logs!

2. Suppress Expected Errors

When you expect errors and they don't matter:

find / -name "*.conf" 2>/dev/null

3. Keep Error Logs Separate

For important operations, keep error logs separate for easier troubleshooting:

./backup_script.sh > backup.log 2> backup_errors.log

4. Use Absolute Paths in Scripts

When redirecting in scripts, use absolute paths to avoid confusion:

# Good
echo "Log" >> /var/log/myapp.log

# Risky (depends on current directory)
echo "Log" >> myapp.log

5. Check Exit Status After Redirecting to /dev/null

Even if output is hidden, check if the command succeeded:

if command &>/dev/null; then
    echo "Success"
else
    echo "Failed"
fi

6. Be Careful with > (Overwrite)

Double-check before using > on important files:

# Dangerous! Overwrites important file
important_command > /etc/passwd  # DON'T DO THIS

# Safer
important_command > /tmp/output.txt

7. Use &> for Modern Syntax

Prefer &> over 2>&1 for readability:

# Modern (clear)
command &> output.txt

# Traditional (less clear)
command > output.txt 2>&1

Common Pitfalls and How to Avoid Them

Pitfall 1: Wrong Order in Redirection

Problem:

command 2>&1 > file  # WRONG ORDER

Why it fails: 2>&1 redirects stderr to wherever stdout is pointing right now (the terminal). Then > file redirects stdout to file, but stderr is still going to the terminal.

Solution:

command > file 2>&1  # CORRECT ORDER
# Or use modern syntax:
command &> file

Pitfall 2: Forgetting to Append

Problem:

for i in {1..5}; do
    echo "Line $i" > log.txt  # BUG: Overwrites each time
done

Result: Only "Line 5" ends up in the file!

Solution:

for i in {1..5}; do
    echo "Line $i" >> log.txt  # Correct: Appends
done

Pitfall 3: Redirecting to the Same File You're Reading

Problem:

sort file.txt > file.txt  # DANGEROUS!

This can corrupt or empty the file because the shell opens file.txt for writing (truncating it) before sort can read it.

Solution:

sort file.txt > file.txt.tmp && mv file.txt.tmp file.txt
# Or use sponge (from moreutils package):
sort file.txt | sponge file.txt

Pitfall 4: Not Quoting File Names with Spaces

Problem:

cat > my file.txt  # Creates two files: "my" and "file.txt"

Solution:

cat > "my file.txt"  # Creates one file: "my file.txt"

Pitfall 5: Thinking > Creates Directories

Problem:

command > /path/to/nonexistent/dir/file.txt
bash: /path/to/nonexistent/dir/file.txt: No such file or directory

Solution: Create the directory first:

mkdir -p /path/to/nonexistent/dir
command > /path/to/nonexistent/dir/file.txt

Pitfall 6: Accidentally Overwriting Important Files

Problem:

ls > /etc/hosts  # DISASTER!

Solution: Enable noclobber in bash to prevent accidental overwrites:

set -o noclobber
ls > /etc/hosts
bash: /etc/hosts: cannot overwrite existing file

# Force overwrite if needed:
ls >| /etc/hosts

I/O Redirection Command Cheat Sheet

OperatorDescriptionExample
>Redirect stdout, overwrite filels > files.txt
>>Redirect stdout, append to fileecho "text" >> log.txt
<Redirect stdin from filesort < names.txt
2>Redirect stderr, overwritecommand 2> errors.txt
2>>Redirect stderr, appendcommand 2>> errors.txt
&>Redirect both stdout and stderrcommand &> all.txt
&>>Redirect both, appendcommand &>> all.txt
2>&1Redirect stderr to stdoutcommand > file 2>&1
1>&2Redirect stdout to stderrecho "error" 1>&2
>/dev/nullDiscard stdoutcommand >/dev/null
2>/dev/nullDiscard stderrcommand 2>/dev/null
&>/dev/nullDiscard all outputcommand &>/dev/null
> (no command)Create/clear file> empty.txt

Practice Labs

Let's practice I/O redirection with hands-on exercises. Try to solve each task before looking at the solution.

Lab 1: Basic Output Redirection

Task: List all files in your home directory and save the output to homedir.txt.

Solution
ls ~ > homedir.txt
# Or:
ls -la ~ > homedir.txt

# Verify:
cat homedir.txt

Lab 2: Append to File

Task: Create a file called fruits.txt with "apple" on the first line. Then append "banana", "cherry", and "date" on separate lines.

Solution
echo "apple" > fruits.txt
echo "banana" >> fruits.txt
echo "cherry" >> fruits.txt
echo "date" >> fruits.txt

# Verify:
cat fruits.txt
apple
banana
cherry
date

Lab 3: Input Redirection

Task: Create a file numbers.txt with numbers 5, 2, 8, 1, 9 (one per line). Use input redirection to sort the numbers and display the result.

Solution
# Create file:
cat > numbers.txt
5
2
8
1
9
# Press Ctrl-D

# Sort using input redirection:
sort < numbers.txt
1
2
5
8
9

Lab 4: Combined Input and Output Redirection

Task: Sort the numbers.txt file from Lab 3 and save the sorted output to sorted_numbers.txt.

Solution
sort < numbers.txt > sorted_numbers.txt

# Verify:
cat sorted_numbers.txt
1
2
5
8
9

Lab 5: Redirecting Errors Only

Task: Try to list the directory /root (which you likely don't have permission to access) and redirect any error messages to access_errors.txt.

Solution
ls /root 2> access_errors.txt

# Verify the error was captured:
cat access_errors.txt
ls: cannot access '/root': Permission denied

Lab 6: Separate Output and Errors

Task: Run ls /home /nonexistent /tmp and redirect normal output to output.txt and errors to errors.txt.

Solution
ls /home /nonexistent /tmp > output.txt 2> errors.txt

# Check normal output:
cat output.txt
/home:
user1
/tmp:
file1

# Check errors:
cat errors.txt
ls: cannot access '/nonexistent': No such file or directory

Lab 7: Redirect Both Streams Together

Task: Search for the word "root" in all files under /etc and redirect all output (both matches and errors) to search_all.txt.

Solution
grep root /etc/* &> search_all.txt

# Or using traditional syntax:
grep root /etc/* > search_all.txt 2>&1

# View first few lines:
head search_all.txt

Lab 8: Discard Errors with /dev/null

Task: Find all files named *.conf starting from the root directory, but suppress permission denied errors.

Solution
find / -name "*.conf" 2>/dev/null

Lab 9: Discard All Output

Task: Run the command grep -r "test" /etc but don't display any output at all (neither matches nor errors).

Solution
grep -r "test" /etc &>/dev/null

# Or:
grep -r "test" /etc >/dev/null 2>&1

Lab 10: Create an Empty File

Task: Create an empty file called placeholder.txt using only redirection (no touch command).

Solution
> placeholder.txt

# Verify:
ls -l placeholder.txt
-rw-r--r--. 1 user user 0 Dec 11 15:30 placeholder.txt

Lab 11: Clear a File's Contents

Task: Create a file with some content, then clear its contents using redirection without deleting the file.

Solution
# Create file with content:
echo "This will be cleared" > test_clear.txt

# Verify it has content:
cat test_clear.txt
This will be cleared

# Clear it:
> test_clear.txt

# Verify it's empty:
cat test_clear.txt
# (no output)

ls -l test_clear.txt
-rw-r--r--. 1 user user 0 Dec 11 15:32 test_clear.txt

Lab 12: Build a System Info Report

Task: Create a file sysinfo.txt that contains the output of these commands on separate lines: hostname, date, uname -r, and uptime.

Solution
hostname > sysinfo.txt
date >> sysinfo.txt
uname -r >> sysinfo.txt
uptime >> sysinfo.txt

# Verify:
cat sysinfo.txt
vm1.example.com
Wed Dec 11 15:35:22 EST 2025
5.14.0-362.el9.x86_64
 15:35:22 up  2:15,  2 users,  load average: 0.15, 0.22, 0.18

Lab 13: Filter Command Output

Task: Get a list of all running processes, save to processes.txt, then search that file for processes containing "ssh" and save results to ssh_processes.txt.

Solution
ps aux > processes.txt
grep ssh < processes.txt > ssh_processes.txt

# Or combine:
grep ssh processes.txt > ssh_processes.txt

# Verify:
cat ssh_processes.txt

Lab 14: Dealing with Permission Errors

Task: Use grep to search for "centos" in all files under /etc, suppress errors, and save only successful matches to matches.txt.

Solution
sudo grep -r "centos" /etc 2>/dev/null > matches.txt

# Verify:
head matches.txt

Lab 15: Create a Log File Entry

Task: Append a timestamped log entry to app.log that says "Application started".

Solution
echo "$(date): Application started" >> app.log

# Verify:
cat app.log
Wed Dec 11 15:40:15 EST 2025: Application started

# Add more entries:
echo "$(date): Processing data" >> app.log
echo "$(date): Application stopped" >> app.log

cat app.log
Wed Dec 11 15:40:15 EST 2025: Application started
Wed Dec 11 15:40:22 EST 2025: Processing data
Wed Dec 11 15:40:28 EST 2025: Application stopped

Lab 16: Test Command Success Silently

Task: Write a command that tests if the directory /var/log exists by using ls, but suppress all output. Then use echo $? to check the exit status.

Solution
ls /var/log &>/dev/null
echo $?
0

# Try with non-existent directory:
ls /nonexistent &>/dev/null
echo $?
2

Exit status 0 means success (directory exists). Non-zero means failure.

Lab 17: Redirect to Multiple Destinations

Task: Save your current directory's detailed listing to both list1.txt and list2.txt (without using pipes for now).

Solution
ls -la > list1.txt
ls -la > list2.txt

# Verify both files:
diff list1.txt list2.txt
# (no output means files are identical)

Note: In the next post, we'll learn about tee which makes this easier.

Lab 18: Simulating Command Logging

Task: Create a simple "command log" by redirecting the output of several commands to command_log.txt. Include: current user, current directory, date, and list of files.

Solution
{
    echo "=== Command Log ==="
    echo "User: $(whoami)"
    echo "Directory: $(pwd)"
    echo "Date: $(date)"
    echo "Files:"
    ls -l
} > command_log.txt

# Verify:
cat command_log.txt

Lab 19: Error Log Analysis

Task: Run the command find /etc -type f -name "*.conf" and save only the error messages to find_errors.log, while displaying the found files on screen.

Solution
find /etc -type f -name "*.conf" 2> find_errors.log

# Normal output (files found) displays on screen
# Errors go to find_errors.log

# Check errors:
cat find_errors.log
find: '/etc/audit': Permission denied
find: '/etc/polkit-1/rules.d': Permission denied
...

Lab 20: Advanced: Separate Logging Script

Task: Create a script that runs df -h and free -h, saving normal output to stats.log and any errors to stats_errors.log, with timestamps for each command.

Solution
#!/bin/bash

{
    echo "=== Disk Usage at $(date) ==="
    df -h
    echo ""
    echo "=== Memory Usage at $(date) ==="
    free -h
} >> stats.log 2>> stats_errors.log

# Make it executable:
chmod +x stats_script.sh

# Run it:
./stats_script.sh

# Check the log:
cat stats.log
=== Disk Usage at Wed Dec 11 15:50:00 EST 2025 ===
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   20G   28G  42% /

=== Memory Usage at Wed Dec 11 15:50:00 EST 2025 ===
              total        used        free      shared  buff/cache   available
Mem:           7.7G        2.1G        3.2G        156M        2.4G        5.1G
Swap:          2.0G          0B        2.0G

Key Takeaways

  1. Three Standard Streams: Every command has stdin (0), stdout (1), and stderr (2)

  2. Output Redirection:

    • > redirects stdout and overwrites the file
    • >> redirects stdout and appends to the file
  3. Input Redirection:

    • < redirects stdin from a file
  4. Error Redirection:

    • 2> redirects stderr
    • 2>&1 redirects stderr to stdout
    • &> redirects both stdout and stderr (modern syntax)
  5. The Black Hole:

    • /dev/null discards any data sent to it
    • Use 2>/dev/null to suppress errors
    • Use &>/dev/null to suppress everything
  6. Order Matters:

    • command > file 2>&1 works correctly
    • command 2>&1 > file doesn't work as expected
  7. Append vs Overwrite:

    • Use >> for logs to avoid data loss
    • Use > carefully—it erases the existing file
  8. Practical Uses:

    • Save command output for later analysis
    • Create automated reports and logs
    • Suppress expected errors to reduce noise
    • Separate error logs from normal operation logs
    • Build reusable script outputs

What's Next?

You now understand how to control where command input comes from and where output goes. In the next post, Part 47: Using Pipes and the tee Command, we'll learn how to:

  • Connect commands together with pipes (|)
  • Chain multiple commands to build powerful data processing pipelines
  • Use tee to send output to both files and the screen simultaneously
  • Combine pipes with redirection for advanced workflows
  • Build real-world system administration pipelines

Pipes are one of the most powerful features of Linux, allowing you to combine simple commands into sophisticated data processing workflows. See you in the next post!

Thank you for reading!

Published on January 6, 2026

Owais

Written by Owais

I'm an AIOps Engineer with a passion for AI, Operating Systems, Cloud, and Security—sharing insights that matter in today's tech world.

I completed the UK's Eduqual Level 6 Diploma in AIOps from Al Nafi International College, a globally recognized program that's changing careers worldwide. This diploma is:

  • ✅ Available online in 17+ languages
  • ✅ Includes free student visa guidance for Master's programs in Computer Science fields across the UK, USA, Canada, and more
  • ✅ Comes with job placement support and a 90-day success plan once you land a role
  • ✅ Offers a 1-year internship experience letter while you study—all with no hidden costs

It's not just a diploma—it's a career accelerator.

👉 Start your journey today with a 7-day free trial

Related Articles

Continue exploring with these handpicked articles that complement what you just read

45 min read

LFCS Part 52: Bash Startup Files and Configuration (FINAL POST!)

Master bash startup and configuration files. Learn the difference between login and non-login shells, understand /etc/profile, ~/.bashrc, ~/.bash_profile, and when to modify each file. Complete guide with practical examples and 20 hands-on labs for LFCS certification preparation.

#linux#lfcs+6 more
Read article

More Reading

One more article you might find interesting