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 > fileThis replaces the content of
filewith the stdout ofcommand. For example:echo "Hello, world!" > hello.txtPrint and redirect to file:
command | tee fileExample:
echo "Hello, world!" | tee hello.txtThis prints “Hello, world!” to the terminal and also writes it to
hello.txt.
Redirect stderr to a file
Standard way:
command 2> fileSends all errors (stderr) to
file. For example:ls non_existing_file 2> error.logPrint 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>&1Combines stdout and stderr into one stream and saves them to
file. For example:ls non_existing_file existing_file > output.log 2>&1Print and redirect both to file:
command 2>&1 | tee fileExample:
ls non_existing_file existing_file 2>&1 | tee output.logConvenient shorthand:
command &> fileExample:
ls non_existing_file existing_file &> output.log
Append instead of overwriting
Append stdout to a file:
command >> fileExample:
echo "Appending line" >> hello.txtPrint and append stdout to file:
command | tee -a fileExample:
echo "Appending line" | tee -a hello.txtAppend both stdout and stderr (explicit):
command >> file 2>&1Example:
ls non_existing_file existing_file >> output.log 2>&1Print and append both stdout and stderr to file:
command 2>&1 | tee -a fileExample:
ls non_existing_file existing_file 2>&1 | tee -a output.logConvenient shorthand for appending both:
command &>> fileExample:
ls non_existing_file existing_file &>> output.log
Piping output
Pipe stdout to another command
Basic usage:
command1 | command2This sends the stdout of
command1to the input ofcommand2. For example:echo "Hello, world!" | grep "Hello"Print and redirect piped stdout to file:
command1 | tee file | command2Example:
echo "Hello, world!" | tee output.txt | grep "Hello"
Pipe both stdout and stderr
Common way:
command1 2>&1 | command2Combines 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 | command2Example:
ls non_existing_file existing_file 2>&1 | tee output.txt | grep "No"
Shorthand for piping both stdout and stderr (|&)
Shorthand syntax:
command1 |& command2This 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 | command2Example:
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 >&3This sends the stdout of
commandto file descriptor3, which points tooutputfile. For example:exec 3> custom_output.txt echo "Using FD 3" >&3Print and redirect stdout to custom file descriptor:
exec 3> custom_output.txt echo "Using FD 3" | tee /dev/tty > /dev/fd/3This 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>&3Redirects stderr to file descriptor
3. For example:exec 3> error_output.txt ls non_existing_file 2>&3Print 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>&1Combines 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>&1Silences all output (stdout and stderr). For example:
ls non_existing_file > /dev/null 2>&1Print and discard stdout and stderr (not sure why you’d ever need this):
command | tee /dev/nullExample:
ls non_existing_file | tee /dev/nullConvenient shorthand:
command &>/dev/nullExample:
ls non_existing_file &>/dev/null
At a glance
Redirect stdout:
command > fileRedirect stderr:
command 2> fileRedirect both stdout and stderr:
- Standard:
command > file 2>&1 - Shorthand:
command &> file
- Standard:
Append stdout:
command >> fileAppend both stdout and stderr:
- Standard:
command >> file 2>&1 - Shorthand:
command &>> file
- Standard:
Pipe stdout:
command1 | command2Pipe 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
- Revisiting interface segregation in Go
- Avoiding collisions in Go context keys
- Organizing Go tests
- Subtest grouping in Go
- Let the domain guide your application structure
- Test state, not interactions
- Early return and goroutine leak
- Lifecycle management in Go tests
- Gateway pattern for external service calls
- Flags for discoverable test config in Go