Bash Redirection

Controlling input and output streams

↔️ What is Redirection?

Redirection controls where command input comes from and where output goes. Instead of displaying on screen, you can send output to files, read input from files, or discard unwanted output entirely.

#!/bin/bash
# Redirect output to file
echo "Hello" > output.txt

Key Redirection Concepts

📤

Output Redirection

Send output to files

cmd > file.txt
📥

Input Redirection

Read input from files

cmd < file.txt

Append Mode

Add to existing files

cmd >> file.txt
⚠️

Error Redirection

Handle error messages

cmd 2> errors.txt

🔹 Output Redirection

The > operator redirects standard output to files, overwriting existing content, while >> appends instead. This is fundamental for saving command results, creating logs, and storing data. Files are created automatically if they don't exist. Combined with error redirection, output control enables comprehensive logging and data capture for automation and debugging.

#!/bin/bash
# output-redirect.sh

# Overwrite file
echo "First line" > output.txt

# Append to file
echo "Second line" >> output.txt
echo "Third line" >> output.txt

# Save command output
ls -l > filelist.txt
date > timestamp.txt

File Contents:

output.txt:
First line
Second line
Third line

🔹 Input Redirection

The < operator redirects standard input from files instead of keyboard input, enabling batch processing and automation. Commands read file content as if it were typed interactively. This is essential for feeding data to programs expecting interactive input, processing configuration files, and automating tasks that normally require user interaction.

#!/bin/bash
# input-redirect.sh

# Read from file
wc -l < input.txt

# Sort file contents
sort < names.txt

# Process file data
while read line; do
    echo "Processing: $line"
done < data.txt

Output:

42
Alice
Bob
Processing: item1

🔹 Error Redirection

Standard error (file descriptor 2) can be redirected separately using 2> to isolate error messages from normal output. This creates cleaner logs by separating successful operations from errors and warnings. Simultaneous redirection of output and errors to different files enables comprehensive logging while maintaining the distinction between regular and error conditions.

#!/bin/bash
# error-redirect.sh

# Redirect errors only
ls /nonexistent 2> errors.txt

# Redirect output and errors separately
ls /tmp > output.txt 2> errors.txt

# Discard errors
ls /invalid 2> /dev/null

# Redirect both to same file
ls /tmp > all.txt 2>&1

File Contents:

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

🔹 Combining Output and Errors

Use 2>&1 to redirect stderr to stdout's destination, or &> to redirect both streams in one operation. This captures all output including errors in single files for complete command histories. Combined with tee, you can simultaneously monitor output while saving comprehensive logs that include both successful results and error messages.

#!/bin/bash
# combine-streams.sh

# Redirect both to same file (method 1)
command > output.txt 2>&1

# Redirect both to same file (method 2)
command &> output.txt

# Append both to same file
command >> log.txt 2>&1

# Discard all output
command &> /dev/null

Usage:

$ ./script.sh &> complete.log
[All output and errors saved to complete.log]

🔹 Here Documents

Here documents (heredoc) provide multi-line input directly in scripts using < syntax until the delimiter appears on its own line. This eliminates the need for separate input files when commands require multi-line input. Heredocs are perfect for embedding configuration files, SQL queries, or documentation within scripts, making them self-contained and portable.

#!/bin/bash
# heredoc-demo.sh

# Create file with multiple lines
cat > config.txt << EOF
server=localhost
port=8080
timeout=30
EOF

# Send multi-line input to command
mysql -u root << SQL
CREATE DATABASE mydb;
USE mydb;
CREATE TABLE users (id INT, name VARCHAR(50));
SQL

File Contents:

config.txt:
server=localhost
port=8080
timeout=30

🔹 Here Strings

Here strings (<<<) pass single strings directly as input to commands without echo or pipelines, improving efficiency and readability. This is cleaner than echo "string" | command and avoids creating subshells. Here strings are particularly useful for passing variable content to commands that read from stdin, creating more efficient and maintainable code.

#!/bin/bash
# herestring-demo.sh

# Pass string as input
grep "error" <<< "This is an error message"

# Use with variables
TEXT="Hello World"
wc -w <<< "$TEXT"

# Multiple commands
while read word; do
    echo "Word: $word"
done <<< "one two three"

Output:

This is an error message
2
Word: one
Word: two
Word: three

🔹 File Descriptors

Bash uses file descriptors to manage I/O streams: 0 (stdin), 1 (stdout), 2 (stderr), with 3-9 available for custom operations. Custom file descriptors enable advanced I/O including simultaneous reading/writing to multiple files, complex redirection patterns, and temporary stream manipulation. This provides fine-grained control over input and output handling in sophisticated scripts.

#!/bin/bash
# file-descriptors.sh

# Open file descriptor 3 for reading
exec 3< input.txt
read -u 3 line
echo "Read: $line"
exec 3<&-  # Close descriptor 3

# Open file descriptor 4 for writing
exec 4> output.txt
echo "Data" >&4
exec 4>&-  # Close descriptor 4

Output:

Read: First line from input.txt

🧠 Test Your Knowledge

Which operator appends output to a file without overwriting?