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 intocommand2."
Example:
grep "ERROR" server.log | wc -l
This:
- finds lines containing
ERROR - sends those lines into
wc -l - 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:
grepto filterheadto 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:
- runs the command pipeline
- captures the output into
error_count - 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.