Input And Output Redirection In Linux

10 min read

Input and output redirection in Linux is a fundamental concept that allows users to control where command input comes from and where output goes, enabling powerful automation, scripting, and efficient data handling. This article provides a thorough look to understanding and using redirection operators, from basic concepts to advanced techniques, ensuring you can manipulate file descriptors and streamline your workflow effectively Still holds up..

Understanding Standard Streams in Linux

Before diving into redirection, it’s essential to grasp the concept of standard streams. Linux (and most Unix-like systems) defines three standard streams for every process:

  1. Standard Input (stdin) – The default input source, typically your keyboard. File descriptor number 0.
  2. Standard Output (stdout) – The default output destination, usually your terminal screen. File descriptor number 1.
  3. Standard Error (stderr) – Used for error messages and diagnostics, also displayed on the terminal. File descriptor number 2.

Redirection involves changing these default associations, allowing you to feed data from files into commands, send output to files, or separate error messages from normal output.

Common Redirection Operators

Linux provides a variety of redirection operators to manipulate these streams. Here are the most frequently used ones:

  • < – Redirects standard input from a file to a command.
  • > – Redirects standard output from a command to a file (overwrites existing content).
  • >> – Appends standard output to a file without overwriting.
  • 2> – Redirects standard error to a file or device.
  • 2>> – Appends standard error to a file.
  • &> or >& – Redirects both standard output and standard error to the same destination.
  • | – Pipes the standard output of one command as input to another.
  • << – Here-document, providing input inline within a script.
  • <<< – Here-string, a simpler alternative to here-documents for single-line input.

Input Redirection with <

Input redirection allows commands to read data from a file instead of the keyboard. To give you an idea, if you have a command that expects input (like wc -l for counting lines), you can provide a file directly:

wc -l < myfile.txt

This counts the lines in myfile.txt without needing to specify the file as an argument. Another practical use is with commands that require configuration or data files, such as sort < unsorted.On top of that, txt > sorted. txt.

Output Redirection: Capturing Command Results

Output redirection is one of the most common uses, enabling you to save command results to files for later analysis or logging. The > operator overwrites the destination file, while >> appends to it.

Example: Overwriting Output

ls -la > directory_listing.txt

This saves the detailed directory listing to directory_listing.txt. If the file exists, its contents are replaced.

Example: Appending Output

echo "New log entry" >> application.log

This adds a new line to the existing application.log file without deleting previous entries Less friction, more output..

Redirecting Standard Error Separately

By default, error messages are sent to stderr, which is displayed on the terminal even if stdout is redirected. To capture errors separately, use 2>:

ls /nonexistent_directory 2> error.log

This sends the error message to error.log while stdout (if any) remains on the screen. To discard errors entirely, redirect to /dev/null:

command 2>/dev/null

Combining Output and Error

In scripts, it’s often useful to capture both stdout and stderr in the same file. Use &> or >&:

./script.sh &> output_and_error.log

This consolidates all output and errors into a single log file, simplifying debugging.

Pipes: Chaining Commands

Pipes (|) connect the stdout of one command to the stdin of another, creating a pipeline. This avoids intermediate files and enables complex data processing:

cat myfile.txt | grep "error" | sort | uniq -c

This pipeline reads myfile.txt, filters lines containing "error", sorts them, and counts duplicates.

Pipes can be combined with redirection for even greater flexibility:

grep "pattern" logfile.txt | wc -l > match_count.txt

Here-Documents and Here-Strings

For inline input, here-documents (<<) allow multi-line input directly in scripts:

cat << EOF > output.txt
This is line 1.
This is line 2.
EOF

Here-strings (<<<) provide a single-line alternative:

read name <<< "John Doe"
echo "Hello, $name"

Practical Examples and Use Cases

1. Logging Script Output

#!/bin/bash
./backup_script.sh > backup.log 2>&1

This runs a backup script, saving both normal output and errors to backup.log And that's really what it comes down to..

2. Silencing Unwanted Output

find / -name "*.tmp" 2>/dev/null > tmp_files.txt

This searches for temporary files, ignoring permission errors (sent to /dev/null), and lists results in a file Most people skip this — try not to..

3. Processing Data with Pipes and Redirection

cut -d',' -f2 data.csv | sort | uniq -c > summary.txt

This extracts the second column from a CSV, sorts unique values, and counts occurrences The details matter here..

4. Interactive Input Redirection in Scripts

while read line; do
  echo "Processing: $line"
done < input_list.txt

This reads each line from input_list.txt and processes it in a loop Not complicated — just consistent..

Advanced Techniques: File Descriptor Manipulation

Beyond the standard streams, you can manipulate additional file descriptors. Here's one way to look at it: to save stdout to one file and stderr to another:

command 1> stdout.log 2> stderr.log

Or, to duplicate a file descriptor (e.g., make stderr follow stdout):

command 3>&1 1>output.log 2>&3

This temporarily redirects stdout to output.log while ensuring stderr goes to the original stdout (terminal).

Common Pitfalls and Tips

  • Order Matters: Redirections are processed left to right. 2>&1 before 1>file will send stderr to the original stdout, not the file.
  • Overwriting vs. Appending: Use > cautiously to avoid accidental data loss. Prefer >> for logs.
  • Quoting and Spaces: When redirecting to files with spaces, quote the filename: > "my file.txt".
  • Permissions: Ensure you have write access to the target directory or file.

Conclusion

Mastering input and output redirection in Linux is a critical skill for anyone working with command-line tools, scripting, or system administration. Practically speaking, by understanding how to control data flow using operators like <, >, 2>, and |, you can automate tasks, debug efficiently, and handle data with precision. Worth adding: whether you’re a beginner or an advanced user, these techniques will enhance your productivity and deepen your command of the Linux environment. Practice with real-world scenarios to internalize these concepts, and you’ll find redirection to be an indispensable part of your toolkit.

Building on the foundation of basic redirection, Linux offers several powerful mechanisms that let you shape data flow in more sophisticated ways. Mastering these tools can turn simple command‑line tricks into strong, reusable patterns for automation, monitoring, and integration It's one of those things that adds up. That's the whole idea..

Using exec for Persistent Redirection

When you need to redirect the input or output of an entire script—or a large block of commands—repeating redirection operators on every line quickly becomes tedious. The exec built‑in changes the file descriptors for the current shell (or subshell) and affects all subsequent commands unless overridden.

# Redirect all stdout of the script to a log file, stderr to a separate error log
exec 1>>script_output.log 2>>script_error.log

# Any command from this point on inherits the redirection
date
ls -l /nonexistent
echo "This goes to the log"

You can also duplicate or swap descriptors:

# Save original stdout, redirect stdout to a file, then restore later
exec 3>&1          # fd 3 becomes a copy of fd 1 (original stdout)
exec 1>output.log  # fd 1 now points to the log file
# … commands that write to output.log …
exec 1>&3          # restore stdout from fd 3
exec 3>&-          # close the temporary copy

Process Substitution

Bash (and other modern shells) lets you treat the output of a command as if it were a file, using <(command) for input and >(command) for output. This eliminates the need for temporary files in many pipelines.

# Compare the sorted, unique contents of two files without temporary files
diff <(sort file1.txt | uniq) <(sort file2.txt | uniq)

# Feed the output of a command to a program that expects a filename
grep -f <(cut -d: -f1 /etc/passwd) /var/log/auth.log

Process substitution works because the shell creates a named pipe (FIFO) or a /dev/fd/* file descriptor behind the scenes, making it transparent to the invoked program And that's really what it comes down to..

Splitting Streams with tee

Sometimes you want to both capture data for later inspection and let it continue down a pipeline. tee reads from standard input and writes copies to each file given as an argument, while also forwarding the data to its own standard output.

# See progress on screen while also logging to a file
./long_running_job.py 2>&1 | tee job.log

# Send the same data to two different processing chains
cat data.csv | tee >(cut -d, -f2 | sort > col2_sorted.txt) \
                 >(cut -d, -f3 | awk '{sum+=$1} END{print sum}' > col3_sum.txt)

Because tee duplicates the stream, each downstream process receives identical data.

Redirecting to and from Network Sockets

Linux treats TCP and UDP ports as pseudo‑files under /dev/tcp and /dev/udp (when the kernel is compiled with support). This enables quick, ad‑hoc network redirection without external tools like netcat And that's really what it comes down to. Worth knowing..

# Send a simple HTTP GET request and capture the response
exec

```bash
# Open a TCP connection to example.com on port 80 and keep it as fd 5
exec 5<>/dev/tcp/example.com/80

# Send a minimal HTTP request (the trailing newline is required)
printf "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" >&5

# Read the response line‑by‑line until the server closes the socket
while IFS= read -r line <&5; do
    echo "Server: $line"
done

# Clean up the custom descriptor
exec 5>&-
exec 5<&-

The snippet above demonstrates how exec can bind a regular file descriptor to a network socket, allowing the script to read from and write to the connection just like any other file. Because the descriptor is attached to the current shell, any subsequent command that inherits the environment will also see fd 5 unless it is explicitly closed or reassigned Easy to understand, harder to ignore..

Replacing the shell with exec

When a script no longer needs its own environment, exec can be used to discard the current shell process and replace it with another program. This is useful for:

  • Tightening resource usage – launching a long‑running daemon without an extra subshell.
  • Signal handling – ensuring that signals are delivered directly to the target process rather than to a wrapper script.
  • Consistent working directory or environment – starting a program with a clean slate.
# Switch from the wrapper script to the actual utility, preserving $PWD
exec /usr/bin/python3 my_script.py

After this line, the original Bash process no longer exists; any subsequent commands in the file are never executed.

Managing unused descriptors

Leaving file descriptors open can lead to leaks, especially in loops that spawn many subprocesses. A disciplined practice is to close descriptors that are no longer needed:

# Close fd 3 if it is still pointing at the temporary log file
exec 3>&-

Doing this after the log has been written guarantees that the descriptor does not linger unintentionally.

Combining exec with process substitution

Because process substitution creates temporary FIFOs or /dev/fd entries, exec can be employed to bind a descriptor directly to the output of a command without an intermediate file:

# Capture the list of running processes as a read‑only stream
exec 4< <(ps -e -o pid,cmd --no-headers)

# Use the stream in a while‑read loop
while IFS= read -r line <&4; do
    echo "PID $line is active"
done
exec 4<&-

Here the shell opens fd 4 for reading the output of ps, allowing the loop to process each line without creating a temporary file Still holds up..

Summary

  • exec reassigns or creates file descriptors for the current shell, influencing all subsequent commands unless they override the redirection.
  • It can duplicate, swap, or close descriptors, enabling patterns such as “save‑and‑restore” or “temporary‑only” redirections.
  • When paired with process substitution, exec lets you treat command output as a persistent stream, which is handy for loops, conditionals, or any code that expects a file.
  • Network sockets exposed as /dev/tcp and /dev/udp provide a lightweight way to perform I/O over the network, and exec makes it straightforward to bind those sockets to descriptors that stay alive for the duration of the script.
  • Closing descriptors promptly and, when appropriate, replacing the shell itself with exec, helps keep resource consumption optimal and avoids accidental side effects.

By mastering exec and its interplay with redirection, process substitution, and the tee utility, scripts become more flexible, efficient, and expressive, allowing complex data flows to be expressed concisely while maintaining clarity and reliability.

More to Read

Fresh Stories

Related Corners

Continue Reading

Thank you for reading about Input And Output Redirection In Linux. 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