The Bash shell is a powerful tool for interacting with Unix-like operating systems, enabling users to execute commands, automate tasks, and manage system resources. One of its most essential features is redirection, which allows you to control where input comes from and where output (including errors) is sent. Whether you’re a beginner learning the command line or an experienced developer writing scripts, mastering redirection will significantly enhance your efficiency and flexibility.
In this guide, we’ll demystify Bash redirections, starting with foundational concepts like file descriptors and standard streams, then diving into practical examples of input/output redirection, error handling, and advanced techniques. By the end, you’ll be able to redirect output to files, capture errors, feed input to commands from files or inline text, and even combine outputs from multiple commands.
Before diving into redirection, we need to understand file descriptors (FDs). A file descriptor is a non-negative integer that the operating system uses to track open files and streams. When a process starts, it inherits three standard file descriptors from its parent (usually the shell):
File Descriptor
Name
Purpose
Default Source/Destination
0
stdin
Standard Input
Keyboard
1
stdout
Standard Output
Terminal (screen)
2
stderr
Standard Error
Terminal (screen)
Redirection lets you change the source (for input) or destination (for output) of these file descriptors.
The 2>&1 syntax redirects stderr (FD 2) to the same destination as stdout (FD 1). This works in all POSIX-compliant shells (not just Bash), making it more portable.
Syntax:
command > combined_output.log 2>&1
Example:
Redirect stdout to output.log, then redirect stderr to stdout (so both go to output.log):
curl https://example.com > output.log 2>&1
⚠️ Note: The order matters! 2>&1 must come after the stdout redirection (>). If you write command 2>&1 > output.log, stderr will redirect to the original stdout (terminal), and only stdout will go to the file.
Process substitution treats the output of a command as a temporary file, allowing you to pass it to another command that expects a file argument. Use <(command) for input (stdout of command as a file) or >(command) for output (write to command as a file).
Syntax:
# Input: Use <(command) as a "file" for another command command1 <(command2)# Output: Write to >(command) as a "file" command1 >(command2)
Examples:
Compare the output of two ls commands with diff:
diff <(ls dir1) <(ls dir2) # Shows differences between listings of dir1 and dir2
Grep a log file and save matches to a file and print to the terminal (using tee):
grep "error" <(tail -f app.log) >(tee errors.log)
Here, <(tail -f app.log) streams the end of app.log, and >(tee errors.log) writes matches to errors.log and stdout.
To redirect all stdout and stderr for an entire script, use exec at the top. exec replaces the current shell process, so redirections set with exec persist for the script’s duration.
Example:
#!/bin/bash # Redirect all output to script.log exec > script.log 2>&1echo "This goes to script.log"ls non_existent_file # Error also goes to script.log
Bash redirection is a cornerstone of command-line mastery, enabling you to control input/output flows, automate tasks, and debug scripts effectively. From simple file redirection with > and < to advanced techniques like process substitution and heredocs, these tools empower you to handle data flexibly in the shell.
Practice with real-world scenarios—like logging script output, capturing errors, or combining command outputs—to solidify your understanding. With redirection in your toolkit, you’ll write more robust scripts and work more efficiently on the command line.