By Davy Rogers. Use these techniques only in environments you own or have explicit permission to test.

Bash: Streams and Redirection

Streams and redirection are fundamental to Unix/Linux philosophy: small programs working together via input/output. Understanding stdin, stdout, stderr, pipes, and redirection will make you exponentially more powerful on the command line. This is one of the most important lessons for mastering Bash.

What You'll Learn

  • Understanding the three streams (stdin, stdout, stderr)
  • Output redirection (>, >>)
  • Input redirection (<)
  • Pipes (|)
  • Combining commands
  • File descriptors
  • Here documents and here strings
  • Practical pentesting workflows

The Three Streams

Standard Input (stdin) - File Descriptor 0

stdin = Standard Input
- Data going INTO a program
- Default: keyboard
- File descriptor: 0

Standard Output (stdout) - File Descriptor 1

stdout = Standard Output
- Normal output FROM a program
- Default: terminal screen
- File descriptor: 1

Standard Error (stderr) - File Descriptor 2

stderr = Standard Error
- Error messages FROM a program
- Default: terminal screen (same as stdout)
- File descriptor: 2

Visualization:

         ┌──────────────┐
stdin  ──┤   Command    ├── stdout
(0)      │              ├── stderr
         └──────────────┘   (2)
            (1)

Output Redirection

Redirect stdout to File

Overwrite file (>):

command > file.txt

Append to file (>>):

command >> file.txt

Examples:

# Save output to file
ls -la > directory_listing.txt

# Append date to log
echo "Scan started: $(date)" >> scan.log

# Save nmap output
nmap 192.168.1.1 > scan_results.txt

# Overwrite previous results
echo "New scan" > results.txt

Redirect stderr to File

Redirect errors (2>):

command 2> errors.txt

Examples:

# Save errors only
find / -name "*.conf" 2> errors.txt

# Discard errors (black hole)
find / -name "*.conf" 2> /dev/null

# Scan without error clutter
nmap 192.168.1.0/24 2> /dev/null

Redirect Both stdout and stderr

Method 1: Redirect separately:

command > output.txt 2> errors.txt

Method 2: Redirect both to same file:

command > combined.txt 2>&1

# Modern bash syntax:
command &> combined.txt

Append both:

command >> combined.txt 2>&1

Examples:

# Save everything
nmap 192.168.1.1 > scan.log 2>&1

# Save output, discard errors
nmap 192.168.1.1 > scan.log 2> /dev/null

# Discard everything
command > /dev/null 2>&1

Input Redirection

Redirect stdin from File

Feed file as input (<):

command < input.txt

Examples:

# Sort file contents
sort < unsorted.txt

# Count lines from file
wc -l < file.txt

# Read from file
while read line; do
    echo "Processing: $line"
done < targets.txt

# MySQL from file
mysql -u root -p database < query.sql

Pipes (|)

Connect Commands

Pipe stdout of command1 to stdin of command2:

command1 | command2

Chain multiple commands:

command1 | command2 | command3 | command4

Common Pipe Patterns

1. Filter output:

# Show only .txt files
ls -la | grep ".txt"

# Find processes
ps aux | grep nginx

# Show open ports
netstat -tuln | grep LISTEN

2. Sort and process:

# Sort files by size
ls -lh | sort -k5

# Count unique IPs
cat access.log | cut -d' ' -f1 | sort | uniq | wc -l

# Top 10 IPs
cat access.log | cut -d' ' -f1 | sort | uniq -c | sort -rn | head -10

3. Search and extract:

# Find open ports in nmap output
nmap 192.168.1.1 | grep "open"

# Extract usernames
cat /etc/passwd | cut -d':' -f1

# Find SUID binaries
find / -perm -4000 2>/dev/null | grep -v "proc"

Combining Streams and Pipes

Complex Pipelines

Example 1: Log analysis:

# Find errors, count by type
cat /var/log/syslog | grep -i error | cut -d' ' -f5- | sort | uniq -c | sort -rn

Example 2: Find large files:

# Find files > 100MB
find / -type f -size +100M 2>/dev/null | xargs ls -lh | sort -k5 -hr

Example 3: Network recon:

# Live hosts from ping sweep
for i in {1..254}; do
    ping -c 1 -W 1 192.168.1.$i 2>/dev/null | grep "64 bytes" | cut -d' ' -f4 | sed 's/:$//' &
done | tee live_hosts.txt

File Descriptors

What Are They?

File Descriptor = Number representing an open file
0 = stdin
1 = stdout
2 = stderr
3+ = Custom file descriptors

Redirect Specific Descriptors

Redirect stdout to file:

command 1> file.txt
# Same as: command > file.txt

Redirect stderr to stdout:

command 2>&1
# stderr goes where stdout goes

Redirect stdout to stderr:

command 1>&2
# stdout goes where stderr goes

Examples:

# Separate output and errors
command 1> output.txt 2> errors.txt

# Send stderr to stdout, pipe both
command 2>&1 | grep "pattern"

# Suppress errors, keep output
command 2>/dev/null

# Suppress output, keep errors
command 1>/dev/null

# Suppress everything
command &>/dev/null
# Or: command > /dev/null 2>&1

Here Documents (<<)

Multi-line Input

Syntax:

command << DELIMITER
line 1
line 2
line 3
DELIMITER

Examples:

1. Create file with heredoc:

cat << EOF > script.sh
#!/bin/bash
echo "Hello, World!"
echo "This is line 2"
EOF

2. SQL commands:

mysql -u root -p database << EOF
CREATE TABLE users (id INT, name VARCHAR(50));
INSERT INTO users VALUES (1, 'Alice');
INSERT INTO users VALUES (2, 'Bob');
EOF

3. SSH commands:

ssh user@remote << EOF
cd /var/www
ls -la
exit
EOF

4. Multi-line echo:

cat << 'EOF'
This is line 1
Variable $HOME is not expanded
EOF

Here Strings (<<<)

Single-line Input

Syntax:

command <<< "string"

Examples:

# Count words in string
wc -w <<< "hello world test"

# Reverse string
rev <<< "hello"

# Base64 encode
base64 <<< "secret"

# MD5 hash
md5sum <<< "password"

# Read into variable
read var1 var2 var3 <<< "one two three"
echo $var2  # Outputs: two

The Black Hole: /dev/null

What Is It?

/dev/null = Null device
- Discards all data written to it
- Returns EOF when read from
- Use to discard unwanted output

Common Uses

Discard errors:

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

Discard output:

command > /dev/null

Discard everything:

command > /dev/null 2>&1

Silent execution:

# Run command silently
./script.sh &> /dev/null

Practical Pentesting Workflows

Workflow 1: Nmap + Analysis

# Scan and save
nmap -sV -p- 192.168.1.1 > scan_full.txt 2>&1

# Extract open ports
cat scan_full.txt | grep "open" | cut -d'/' -f1 > open_ports.txt

# Count services
cat scan_full.txt | grep "open" | wc -l

# Find specific service
cat scan_full.txt | grep -i "ssh"

Workflow 2: Subdomain Enumeration

# Run multiple tools, combine results
subfinder -d example.com -silent > subs1.txt
amass enum -passive -d example.com 2>/dev/null >> subs1.txt

# Remove duplicates
cat subs1.txt | sort -u > unique_subs.txt

# Check for live hosts
cat unique_subs.txt | while read sub; do
    if ping -c 1 -W 1 "$sub" &>/dev/null; then
        echo "$sub" >> live_subs.txt
    fi
done

Workflow 3: Log Analysis

# Analyze web logs
cat access.log | \
    cut -d' ' -f1 | \
    sort | \
    uniq -c | \
    sort -rn | \
    head -20 > top_ips.txt

# Find failed logins
grep "Failed password" /var/log/auth.log | \
    grep -oP '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | \
    sort | \
    uniq -c | \
    sort -rn > failed_login_ips.txt

Workflow 4: Password Cracking

# Crack hashes, save cracked
john hashes.txt --wordlist=rockyou.txt 2>/dev/null | tee crack_progress.txt

# Extract cracked passwords
john --show hashes.txt > cracked.txt

# Statistics
john --show hashes.txt | grep "password hash cracked" | cut -d' ' -f1 > stats.txt

Practical Exercises

Exercise 1: Basic Redirection

# Create test file
ls -la > listing.txt

# Append date
echo "Generated on: $(date)" >> listing.txt

# View result
cat listing.txt

Exercise 2: Error Handling

# Generate errors
find / -name "*.conf" > found.txt 2> errors.txt

# Discard errors
find / -name "*.conf" 2>/dev/null > found_clean.txt

# Save both
find / -name "*.conf" > all_output.txt 2>&1

Exercise 3: Pipes

# Count files
ls -la | wc -l

# Find largest files
ls -lh | sort -k5 -hr | head -5

# Find process
ps aux | grep bash

Exercise 4: Complex Pipeline

# Analyze /etc/passwd
cat /etc/passwd | \
    cut -d':' -f1,3 | \
    sort -t':' -k2 -n | \
    tail -10

# Top 10 largest directories
du -sh /* 2>/dev/null | sort -hr | head -10

Quick Reference

Output Redirection:
command > file               # Overwrite file
command >> file              # Append to file
command 2> file              # Redirect errors
command 2>&1                 # Stderr to stdout
command &> file              # Both to file
command > /dev/null 2>&1     # Discard all

Input Redirection:
command < file               # Read from file
command << EOF               # Here document
command <<< "string"         # Here string

Pipes:
cmd1 | cmd2                  # Connect commands
cmd1 | cmd2 | cmd3           # Chain multiple

File Descriptors:
0 = stdin
1 = stdout  
2 = stderr

Common Patterns:
cmd 2>/dev/null              # Silence errors
cmd | grep pattern           # Filter output
cmd | sort | uniq            # Unique sorted
cmd | wc -l                  # Count lines
cmd | tee file.txt           # Display & save

Resources

Man Pages:

man bash    # Search for "REDIRECTION"

Online:


Next Steps

  1. Practice pipes daily - chain commands together
  2. Master redirection for clean output
  3. Use /dev/null to suppress noise
  4. Build complex pipelines for data processing
  5. Learn tee for simultaneous display and save

Streams and redirection are the heart of command-line power. Master them and you'll work 10x faster!


"| : Because sometimes commands need to talk to each other."