Skip to main content

Pipes, Redirection, and Command Substitution

What are pipes, redirection, and command substitution?

These are three of the most useful ways shell scripts connect commands together.

  • pipes send one command's output into another command
  • redirection sends output into a file
  • command substitution captures a command's output into another command or variable

If shell scripts are glue for command-line tools, these features are some of the most important glue points.

Pipes

A pipe uses |:

command1 | command2

It means:

"Run command1, and send its output into command2."

Example:

grep "ERROR" server.log | wc -l

This:

  1. finds lines containing ERROR
  2. sends those lines into wc -l
  3. counts them

Output might be:

12

Why pipes matter in scripts

Pipes let a script build small workflows from simple commands.

Example:

#!/usr/bin/env bash
grep "ERROR" server.log | head -n 5

This script is tiny, but still useful. It combines two tools:

  • grep to filter
  • head to limit the result

That is a very common shell scripting pattern.

Redirection with > and >>

Redirection sends command output to a file.

Overwrite with >

echo "Start" > log.txt

This writes to log.txt, replacing its old contents if the file already exists.

Append with >>

echo "Another line" >> log.txt

This adds to the end of the file instead of replacing it.

Redirection in scripts

Redirection is very common when scripts save logs, reports, or filtered results.

Example:

#!/usr/bin/env bash
grep -i "error" app.log > errors.txt
echo "Saved results to errors.txt"

This script:

  • searches for matching lines
  • saves them to a file
  • prints a confirmation message

Be careful with >

This is one of the most important beginner warnings:

command > file.txt

overwrites file.txt.

If you meant to keep the previous contents, use:

command >> file.txt

instead.

When a script writes to files, be very clear about whether it should replace or append.

Redirecting both output and errors

Sometimes you want to save both normal output and error output in the same file.

Example:

some_command >>"$log_file" 2>&1

You do not need to master this syntax immediately, but the practical meaning is:

"Append both normal output and error output to the log file."

This is very useful in scripts that log what happened during a run.

Command substitution

Command substitution means:

"Run a command and use its output as a value."

The modern syntax is:

$(command)

Example:

today=$(date +%F)
echo "$today"

Possible output:

2026-04-28

The date +%F command runs first, and its output becomes the value of today.

Why command substitution is useful

It lets a script capture useful information dynamically.

Examples:

  • timestamps
  • current directory names
  • results from grep
  • counts from wc -l
  • output from helper commands

A practical example

#!/usr/bin/env bash

error_count=$(grep -i "error" app.log | wc -l)
echo "Found $error_count error lines"

This script:

  1. runs the command pipeline
  2. captures the output into error_count
  3. prints the result in a readable sentence

This is often easier to work with than trying to visually inspect pipeline output by hand.

Prefer $(...) over backticks

You may see older shell code like this:

today=`date +%F`

Avoid teaching that style as the default.

Prefer:

today=$(date +%F)

It is easier to read and easier to nest safely.

Putting all three together

Here is a small script that uses pipes, redirection, and command substitution together:

#!/usr/bin/env bash

today=$(date +%F)
report_file="errors-$today.txt"

grep -i "error" app.log | head -n 20 >"$report_file"

line_count=$(wc -l <"$report_file")
echo "Saved $line_count lines to $report_file"

What this script does:

  • captures today's date
  • builds a report file name
  • pipes filtered log lines into head
  • redirects the result into a file
  • counts the saved lines
  • prints a summary

This is a great example of what shell scripts are good at: connecting small tools into a repeatable task.

A quick note on <

In:

line_count=$(wc -l <"$report_file")

the < sends the file into the command as input.

You do not need to use input redirection constantly as a beginner, but it is worth recognizing when you see it.

Common mistakes

Overwriting when you meant to append

Use >> for logs you want to grow over time.

Forgetting to quote file variables

Use:

>"$report_file"

not:

>$report_file

Using backticks by default

Prefer $(...) for command substitution.

Building huge one-liners too early

Pipes are powerful, but readability matters. In scripts, it is often better to split complex workflows into a few understandable steps.

Best practices

  • Use pipes to connect simple commands into small workflows
  • Use > when you intentionally want to replace a file
  • Use >> when you want to keep previous output
  • Use $(...) to capture command output cleanly
  • Quote file variables in redirections
  • Keep pipelines readable enough that someone else can explain them

Summary

  • Pipes send one command's output into another command.
  • Redirection sends output into files.
  • Command substitution captures command output as a value.
  • > overwrites; >> appends.
  • Prefer $(...) over backticks.
  • These features are some of the most powerful ways shell scripts connect small tools together.