Linux Redirection and Pipes
last modified October 23, 2026
Redirection and pipes control where commands read their input and where they write their output. Instead of the terminal, a command can read from a file and write to a file, and the output of one command can become the input of another. These features are provided by the shell, not by the individual commands, so they work the same way for every program.
Every process starts with three open file descriptors: standard input
(stdin, 0), standard output (stdout, 1), and
standard error (stderr, 2). By default, all three are connected
to the terminal. The examples use Bash.
Redirecting output
The > operator sends standard output to a file.
echo "first" > out.txt echo "second" > out.txt
The file is created if it does not exist. If it exists, it is truncated before the command runs, so the second command replaces the contents.
$ echo "first" > out.txt $ cat out.txt first $ echo "second" > out.txt $ cat out.txt second
Appending output
The >> operator appends to the end of a file instead of
overwriting it.
echo "third" >> out.txt
Appending is the usual way to write log files.
$ echo "third" >> out.txt $ cat out.txt second third
Redirecting input
The < operator connects a file to standard input.
wc -l < words.txt tr a-z A-Z < words.txt | head -n 3
When wc gets a file name, it prints the name with the count.
With input redirection, it reads anonymous data from standard input and
prints only the number. Some commands, such as tr, read only from
standard input.
$ wc -l words.txt 7 words.txt $ wc -l < words.txt 7 $ tr a-z A-Z < words.txt | head -n 3 SKY FOREST FALCON
Redirecting standard error
Error messages go to standard error, which is redirected with
2>, where 2 is the file descriptor number.
ls words.txt missing.txt 2> errors.txt ls words.txt missing.txt > found.txt 2> errors.txt
The ls command writes the found file to standard output and the
error about the missing one to standard error. Redirecting each stream to a
different file separates results from errors. The > operator
is a shorthand for 1>.
$ ls words.txt missing.txt ls: cannot access 'missing.txt': No such file or directory words.txt $ ls words.txt missing.txt 2> errors.txt words.txt $ cat errors.txt ls: cannot access 'missing.txt': No such file or directory $ ls words.txt missing.txt > found.txt 2> errors.txt $ cat found.txt words.txt
Redirecting both streams
The 2>&1 construct duplicates standard error onto
standard output, so both end up in the same place.
ls words.txt missing.txt > all.txt 2>&1 ls words.txt missing.txt 2>&1 > all.txt ls words.txt missing.txt &> all.txt
Redirections are processed from left to right, so the order matters. In the
first command, standard output goes to the file and then standard error is
pointed to the same place. In the second, standard error is pointed to the
terminal (where standard output was at that moment), and only then is
standard output redirected, so the error is still printed. The
&> operator is a Bash shorthand for the first form;
&>> appends.
$ ls words.txt missing.txt > all.txt 2>&1 $ cat all.txt ls: cannot access 'missing.txt': No such file or directory words.txt $ ls words.txt missing.txt 2>&1 > all.txt ls: cannot access 'missing.txt': No such file or directory $ cat all.txt words.txt $ ls words.txt missing.txt &> all.txt $ cat all.txt ls: cannot access 'missing.txt': No such file or directory words.txt
Discarding output
The special file /dev/null discards everything written to it.
ls words.txt missing.txt 2> /dev/null ls missing.txt > /dev/null 2>&1; echo "exit: $?"
The first command hides error messages. The second discards all output,
which is useful when only the exit status matters; here it is 2, which
ls uses for serious problems such as missing arguments.
$ ls words.txt missing.txt 2> /dev/null words.txt $ ls missing.txt > /dev/null 2>&1; echo "exit: $?" exit: 2
Pipes
The pipe operator | connects the standard output of one command
to the standard input of the next. The commands run concurrently.
sort words.txt | uniq | head -n 3 ls words.txt missing.txt | wc -l ls words.txt missing.txt |& wc -l
The first pipeline sorts the words, removes duplicates, and shows the first
three. A pipe passes only standard output, so in the second pipeline the
error message goes to the terminal and wc counts one line. The
|& operator, a shorthand for 2>&1 |,
passes both streams. To save a copy of the data flowing through a pipe, use
the tee command.
$ sort words.txt | uniq | head -n 3 bear falcon forest $ ls words.txt missing.txt | wc -l ls: cannot access 'missing.txt': No such file or directory 1 $ ls words.txt missing.txt |& wc -l 2
Here documents
A here document feeds lines of text written in the script to the standard input of a command, up to a delimiter line.
#!/bin/bash user="jano" cat <<EOF Report for $user Generated: $(date -d 2026-10-23 +%F) EOF cat <<'EOF' Literal text: $user $(date) EOF
In the first here document, variables and command substitutions are
expanded. When the delimiter is quoted, as in 'EOF', the text is
passed literally. The delimiter can be any word; it must appear alone on the
closing line.
#!/bin/bash if true; then cat <<-EOF indented line one indented line two EOF fi
With <<-, leading tab characters are removed from the
lines and the closing delimiter, so the here document can be indented with
the surrounding code. Only tabs are stripped, not spaces.
$ ./report.sh Report for jano Generated: 2026-10-23 Literal text: $user $(date) $ ./indent.sh indented line one indented line two
Here strings
A here string, written with <<<, passes a single string
to standard input.
wc -w <<< "an old falcon" read -r first rest <<< "sky forest falcon" tr a-z A-Z <<< "hello there"
A newline is appended to the string. Unlike echo ... | read, a
here string lets read run in the current shell, so the variables
are available afterwards.
$ wc -w <<< "an old falcon" 3 $ read -r first rest <<< "sky forest falcon" $ echo "$first | $rest" sky | forest falcon $ tr a-z A-Z <<< "hello there" HELLO THERE
Process substitution
Process substitution, written as <(command), makes the output
of a command available as a file name.
diff <(sort a.txt) <(sort b.txt) comm -12 <(sort a.txt) <(sort b.txt)
Commands like diff and comm expect two file names,
so a single pipe is not enough. Bash runs each sort and passes
special paths such as /dev/fd/63, from which the output can be
read. The >(command) form works in the other direction and
provides a file name that writes to a command.
$ printf "%s\n" sky owl falcon > a.txt; printf "%s\n" owl sky wolf > b.txt $ diff <(sort a.txt) <(sort b.txt) 1d0 < falcon 3a3 > wolf $ comm -12 <(sort a.txt) <(sort b.txt) owl sky $ echo <(true) /dev/fd/63
Protecting files from overwriting
The noclobber option prevents > from
overwriting existing files.
set -o noclobber echo "data" > out.txt echo "data" >| out.txt
With noclobber set, the redirection fails for an existing file.
The >| operator overrides the protection explicitly. The
set +o noclobber command turns the option off.
$ set -o noclobber $ echo "data" > out.txt bash: out.txt: cannot overwrite existing file $ echo "data" >| out.txt $ cat out.txt data
Redirection with exec
The exec builtin without a command applies redirections to the
current shell. This opens additional file descriptors or redirects all
output of a script.
#!/bin/bash exec 3> app.log echo "starting" >&3 echo "visible on terminal" echo "finished" >&3 exec 3>&- cat app.log
We open file descriptor 3 for writing to app.log, send selected
messages to it with >&3, and close it with
3>&-. Normal output still goes to the terminal.
#!/bin/bash exec > run.log 2>&1 echo "step 1" ls /nonexistent echo "step 2"
Here, exec redirects both standard output and standard error of
the rest of the script to run.log, so nothing appears on the
terminal.
$ ./logging.sh visible on terminal starting finished $ ./whole.sh $ cat run.log step 1 ls: cannot access '/nonexistent': No such file or directory step 2
Reading and writing the same file
A common mistake is to redirect the output of a command to the file it reads.
sort words.txt > words.txt
The shell truncates words.txt before sort starts,
so sort reads an empty file and the data is lost. Write to a
temporary file and rename it, or use an option for in-place editing, such as
sort -o words.txt words.txt or sed -i.
$ sort words.txt > words.txt $ wc -l words.txt 0 words.txt
Best practices
- Mind the order: Write
> file 2>&1, not2>&1 > file. - Keep errors visible: Discard standard error only when you know which messages you hide.
- Quote here document delimiters: Use
'EOF'when the text must not be expanded. - Never redirect into the input file: Use a temporary file or an in-place option.
- Use noclobber interactively: It protects against accidental overwrites.
Source
In this article, we have used output, input, and error redirection, pipes,
here documents and here strings, process substitution, and
exec to control the input and output of commands.
Author
List all Linux tutorials.