I always struggle with the syntax for redirecting multiple streams to another command or a file. LLMs do help, but beyond the most obvious cases, it takes a few prompts to get the syntax right. When I know exactly what I’m after, scanning a quick post is much faster than wrestling with a non-deterministic kraken. So, here’s a list of the redirection and piping syntax I use the most, with real examples.
Redirecting stdout and stderr
Redirect stdout to a file
Standard way:
command > file
This replaces the content of
file
with the stdout ofcommand
. For example:echo "Hello, world!" > hello.txt
Print and redirect to file:
command | tee file
Example:
echo "Hello, world!" | tee hello.txt
This prints “Hello, world!” to the terminal and also writes it to
hello.txt
.
Redirect stderr to a file
Standard way:
command 2> file
Sends all errors (stderr) to
file
. For example:ls non_existing_file 2> error.log
Print and redirect stderr to file:
command 2> >(tee file)
Example:
ls non_existing_file 2> >(tee error.log)
Redirect both stdout and stderr to a file
Common approach:
command > file 2>&1
Combines stdout and stderr into one stream and saves them to
file
. For example:ls non_existing_file existing_file > output.log 2>&1
Print and redirect both to file:
command 2>&1 | tee file
Example:
ls non_existing_file existing_file 2>&1 | tee output.log
Convenient shorthand:
command &> file
Example:
ls non_existing_file existing_file &> output.log
Append instead of overwriting
Append stdout to a file:
command >> file
Example:
echo "Appending line" >> hello.txt
Print and append stdout to file:
command | tee -a file
Example:
echo "Appending line" | tee -a hello.txt
Append both stdout and stderr (explicit):
command >> file 2>&1
Example:
ls non_existing_file existing_file >> output.log 2>&1
Print and append both stdout and stderr to file:
command 2>&1 | tee -a file
Example:
ls non_existing_file existing_file 2>&1 | tee -a output.log
Convenient shorthand for appending both:
command &>> file
Example:
ls non_existing_file existing_file &>> output.log
Piping output
Pipe stdout to another command
Basic usage:
command1 | command2
This sends the stdout of
command1
to the input ofcommand2
. For example:echo "Hello, world!" | grep "Hello"
Print and redirect piped stdout to file:
command1 | tee file | command2
Example:
echo "Hello, world!" | tee output.txt | grep "Hello"
Pipe both stdout and stderr
Common way:
command1 2>&1 | command2
Combines stdout and stderr, then pipes the combined stream to
command2
. For example:ls non_existing_file existing_file 2>&1 | grep "No"
Print and redirect both stdout and stderr to file:
command1 2>&1 | tee file | command2
Example:
ls non_existing_file existing_file 2>&1 | tee output.txt | grep "No"
Shorthand for piping both stdout and stderr (|&
)
Shorthand syntax:
command1 |& command2
This is equivalent to
command1 2>&1 | command2
, combining stdout and stderr. For example:ls non_existing_file existing_file |& grep "No"
Print and redirect both stdout and stderr using
|&
:command1 |& tee file | command2
Example:
ls non_existing_file existing_file |& tee output.txt | grep "No"
Redirecting file descriptors
Custom file descriptors
Create a new file descriptor (e.g.,
3
) and redirect stdout to it:exec 3> outputfile command >&3
This sends the stdout of
command
to file descriptor3
, which points tooutputfile
. For example:exec 3> custom_output.txt echo "Using FD 3" >&3
Print and redirect stdout to custom file descriptor:
exec 3> custom_output.txt echo "Using FD 3" | tee /dev/tty > /dev/fd/3
This prints “Using FD 3” to the terminal and simultaneously writes it to
custom_output.txt
.
Redirect stderr to a file descriptor
Common case:
command 2>&3
Redirects stderr to file descriptor
3
. For example:exec 3> error_output.txt ls non_existing_file 2>&3
Print and redirect stderr to custom file descriptor:
command 2> >(tee >(cat > /dev/fd/3))
Example:
ls non_existing_file 2> >(tee >(cat > /dev/fd/3))
Redirect both stdout and stderr to a file descriptor
Common way:
command > /dev/fd/3 2>&1
Combines stdout and stderr, and redirects them to file descriptor
3
.Note: There’s no shorthand equivalent for redirecting both stdout and stderr to a file descriptor. You need to use the full syntax. For example:
exec 3> combined_output.txt ls non_existing_file existing_file > /dev/fd/3 2>&1
Discarding output
Send stdout and stderr to /dev/null
Common:
command > /dev/null 2>&1
Silences all output (stdout and stderr). For example:
ls non_existing_file > /dev/null 2>&1
Print and discard stdout and stderr (not sure why you’d ever need this):
command | tee /dev/null
Example:
ls non_existing_file | tee /dev/null
Convenient shorthand:
command &>/dev/null
Example:
ls non_existing_file &>/dev/null
At a glance
Redirect stdout:
command > file
Redirect stderr:
command 2> file
Redirect both stdout and stderr:
- Standard:
command > file 2>&1
- Shorthand:
command &> file
- Standard:
Append stdout:
command >> file
Append both stdout and stderr:
- Standard:
command >> file 2>&1
- Shorthand:
command &>> file
- Standard:
Pipe stdout:
command1 | command2
Pipe both stdout and stderr:
- Standard:
command1 2>&1 | command2
- Shorthand:
command1 |& command2
- Standard:
Custom file descriptors:
- Create and redirect stdout:
exec 3> file; command >&3
- Redirect stderr:
command 2>&3
- Redirect both stdout and stderr:
command > /dev/fd/3 2>&1
(no shorthand available)
- Create and redirect stdout:
Discard stdout and stderr:
- Standard:
command > /dev/null 2>&1
- Shorthand:
command &>/dev/null
- Standard:
Recent posts
- SSH saga
- Injecting Pytest fixtures without cluttering test signatures
- Explicit method overriding with @typing.override
- Quicker startup with module-level __getattr__
- Docker mount revisited
- Topological sort
- Writing a circuit breaker in Go
- Discovering direnv
- Notes on building event-driven systems
- Bash namerefs for dynamic variable referencing