Linux pipes and redirection: 10 examples that click

Stop retyping terminal commands. Learn how Linux pipes and redirection work through 10 clear, practical examples you can run right now.

By Asahluma Tyika

Stop Typing the Same Commands Twice

When you first open a Linux terminal, every command feels like an island. You run ls to see files, cat to read them, and grep to search them. You copy something from one output, paste it into another tool, and hit Enter.

That manual copying gets old fast.

The real power of Linux comes from the Unix philosophy: write programs that do one thing well, and make them work together. Pipes (|) and redirection (>, <, >>) are the glue that joins those small utilities into fast, custom workflows.

If you are a web developer, a DevOps novice, or a programmer looking to get comfortable on a server, this guide will make standard streams click once and for all.


Part 1: The Three Standard Streams

Every single command you run in Bash automatically opens three data channels:

Stream Name File Descriptor Default Source / Destination What It Does
Standard Input (stdin) 0 Keyboard Data flowing into the command
Standard Output (stdout) 1 Terminal Screen Normal output from the command
Standard Error (stderr) 2 Terminal Screen Error messages produced by the command

By default, both output (stdout) and errors (stderr) print directly to your screen. Redirection simply means telling Linux: “Do not send this to the screen; send it to a file or another device instead.”

Here are the redirection operators you will use daily:

Operator Meaning Example
> Redirect stdout to a file (overwrites existing content) echo "hi" > file.txt
>> Append stdout to a file (preserves existing content) echo "again" >> file.txt
< Read stdin from a file instead of the keyboard sort < names.txt
2> Redirect stderr only ls fake 2> error.log
&> or 2>&1 Redirect both stdout and stderr together npm run build &> build.log
\| Send stdout of one command to stdin of another cat names.txt \| sort

Part 2: Redirection Basics (Examples 1 to 5)

Let’s walk through concrete examples you can run right now on your machine.

Example 1: Overwriting a file with >

The > operator takes the standard output of a command and writes it to a file. If the file already exists, Bash wipes it clean first.

echo "Server status: healthy" > status.txt
cat status.txt

If you run echo "Server status: degraded" > status.txt, the word “healthy” is gone, replaced entirely by “degraded”.

Example 2: Appending to a file with >>

When you want to log events without destroying prior entries, use double arrows (>>).

echo "Backup started: $(date)" >> backup.log
sleep 1
echo "Backup finished: $(date)" >> backup.log
cat backup.log

The file now contains both lines.

Example 3: Silencing or capturing errors with 2>

If you run a command that fails, it writes to stream 2 (stderr). Normal redirection with > will not catch it.

# This prints an error to your terminal screen:
ls /root/secret_folder > output.txt

# This catches the error in errors.log instead:
ls /root/secret_folder 2> errors.log
cat errors.log

If you just want to throw errors away completely, point descriptor 2 to the Linux “black hole” (/dev/null):

ls /root/secret_folder 2> /dev/null

Example 4: Capturing both output and errors (&>)

When running automated scripts, you usually want one log file containing everything that happened—both normal messages and errors.

# Modern Bash syntax
ping -c 1 127.0.0.1 &> network.log
ping -c 1 invalid.domain.example &>> network.log
cat network.log

Alternatively, you will often see the classic portable POSIX syntax:

command > network.log 2>&1

This reads: “Send standard output to network.log, then direct file descriptor 2 (stderr) to wherever file descriptor 1 (stdout) is currently pointing.”

Example 5: Feeding files into commands with <

Instead of having a command ask you for keyboard input, you can feed a file directly into its stdin:

# Create a small list
echo -e "banana\napple\ncherry" > fruits.txt

# Sort reads the file via stdin
sort < fruits.txt

Part 3: Connecting Tools with Pipes (Examples 6 to 7)

Redirection points data toward or away from files. A pipe (|) points data toward another command.

The pipe takes the stdout of the command on the left and connects it directly to the stdin of the command on the right.

[ Command A ] --(stdout)--> | PIPE | --(stdin)--> [ Command B ]

Example 6: Counting items with wc -l

Need to know how many .log files live in /var/log (or your current folder)? Do not count them by hand:

ls -1 | wc -l

ls -1 lists one file per line; wc -l reads those lines from its standard input and counts them.

Example 7: Filtering with grep

Instead of opening a giant file or reading endless console output, pipe it into grep:

# View only the lines containing your username
cat /etc/passwd | grep "$USER"

(Tip: While grep "$USER" /etc/passwd also works directly, using a pipe is invaluable when the input comes from live terminal tools like ps, docker, or git.)


Hands-on Example: Real-World Pipelines (Examples 8 to 10)

Let’s build a mini log-analysis scenario. Copy and paste this block into your terminal to generate a sample web server log:

cat << 'EOF' > access.log
192.168.1.10 - GET /index.html 200
192.168.1.15 - POST /login 401
192.168.1.10 - GET /dashboard 200
10.0.0.5 - GET /index.html 200
192.168.1.15 - POST /login 200
192.168.1.20 - GET /about 404
10.0.0.5 - GET /api/v1/data 500
192.168.1.10 - GET /logout 200
EOF

Now let’s extract meaningful data using chained pipes.

Example 8: Finding unique visitors (sort | uniq)

The uniq command only collapses duplicates that are right next to each other, so you always sort the data first.

Let’s pull the IP addresses (the first column) using cut, sort them, count occurrences, and rank them:

cut -d ' ' -f 1 access.log | sort | uniq -c | sort -nr

Output:

      3 192.168.1.10
      2 192.168.1.15
      2 10.0.0.5
      1 192.168.1.20

You just built a mini analytics engine in 47 characters.

Example 9: Splitting streams with tee

Sometimes you want to see output on your screen and save it to a file at the exact same moment. tee duplicates the stream:

grep "401" access.log | tee unauthorized_access.txt

You will see the matching line on your monitor, but if you run cat unauthorized_access.txt, the data is saved there too.

Example 10: The complete incident report pipeline

Let’s combine pipes, grep, sorting, and file redirection into a single pipeline. We will find every client that triggered a server error (HTTP codes in the 400s or 500s) and save an audit trail:

grep -E " (4[0-9]{2}|5[0-9]{2}) " access.log \
  | cut -d ' ' -f 1,4,5 \
  | sort \
  > incident_report.txt

cat incident_report.txt

Output:

10.0.0.5 GET /api/v1/data 500
192.168.1.15 POST /login 401
192.168.1.20 GET /about 404

Notice how > sat at the very end of the pipeline. The data flowed through three separate utilities in memory before finally hitting the disk.


Common Mistakes / Troubleshooting

  • Wiping a file while trying to read it: Running cat data.txt | grep "active" > data.txt will result in an empty file. The shell opens and empties data.txt with > before cat has a chance to read it. Use a temporary file instead:
    grep "active" data.txt > data.tmp && mv data.tmp data.txt
    
  • Placing 2>&1 in the wrong position: The order matters. Running command 2>&1 > file.log sends stderr to the terminal and stdout to the file. Always put the redirection target first:
    command > file.log 2>&1
    
  • Confusing pipes (|) with redirects (>): Pipes send data to a command. Redirection sends data to a file.
    • Incorrect: ls | output.txt (the shell tries to execute output.txt as a program).
    • Correct: ls > output.txt.
  • Assuming pipes pass errors: A standard pipe | only passes stdout. If the command on the left fails with an error, that error prints to your screen and skips the pipe. In modern Bash, use |& to pipe both stdout and stderr together.

Try It Yourself

Write a single-line command pipeline that:

  1. Lists all running processes using ps aux.
  2. Filters for processes matching the word root.
  3. Counts how many there are.
  4. Appends that final number to a file called root_process_count.txt.
Click here to reveal solution ```bash ps aux | grep "^root" | wc -l >> root_process_count.txt ``` *(Using `^root` ensures you match processes owned by the user root at the start of the line rather than matching the letters "root" inside arbitrary command arguments).*

What’s Next

  • Process Substitution (<()): Learn how to treat the output of a command as a virtual file (e.g., diff <(ls dirA) <(ls dirB)).
  • Text Processing Powerhouses: Take the output from your pipes and manipulate it using awk and sed.
  • Exit Codes and $?: Learn how to check whether piped commands succeeded using the PIPESTATUS array.

Bookmark this page so you have a quick cheat sheet next time you need to tame terminal output.

Share: X (Twitter) Facebook LinkedIn