Thuta Learning
IntermediateDevOps & Toolsbeginner

Pipes, Redirection, and Here-Documents

What you'll walk away with

  • Explain the core ideas behind Pipes, Redirection, and Here-Documents
  • Run the sample code and verify its output
  • Apply the technique correctly to the Tutorial Platform and production scenarios

Build the mental model

Pipes and redirection are how bash connects independent programs together instead of forcing you to write everything as one monolithic script — this is the Unix philosophy in practice: small, focused tools, composed. A pipe (|) connects one command's stdout directly to the next command's stdin, so printf ... | wc -l counts lines without ever writing an intermediate file, and grep -v banana | sort chains a filter into a sort with no temporary state in between — each command in the chain runs concurrently, reading and writing through the pipe as data flows. Redirection operators work on files instead of other commands: > sends a command's stdout to a file, overwriting whatever was there, while >> appends to the end instead, preserving existing content — mixing these up is a common way to accidentally destroy a log file's history. The reason stdout and stderr can be redirected independently, as in 1>out.txt 2>err.txt, is that they are genuinely separate streams under the hood, identified by file descriptors 1 and 2 respectively; 2>&1 merges stderr into wherever stdout is currently pointed, and redirecting unwanted output to /dev/null discards it entirely while still letting the rest of the script's output through normally. Here-documents (<<EOF ... EOF) and here-strings (<<<) invert the whole idea: instead of a command's output going somewhere, they feed literal text into a command's stdin, which is how you generate multi-line content or supply a single value without needing a separate file on disk.

Connect it to a real scenario

A typical CI or deployment script might pipe a command's output through grep to check for an error keyword, redirect noisy-but-unimportant output to /dev/null while still capturing errors for later, or use a here-document to generate a file inline — this lesson's code demonstrates each of these individually so you can see the mechanics clearly. printf "apple\nbanana\ncherry\n" | wc -l shows the simplest pipe: three lines in, a count of 3 out, no file involved. grep -v banana | sort chains further, removing one line and then sorting what remains, which is how a small pipeline replaces what would otherwise be several lines of manual filtering and looping. The redirection block deliberately separates stdout and stderr into two different files using 1>"$out_file" 2>"$out_file.err" inside a { ... } group, which is the pattern you'd use in a real script to keep normal output and error output in separate logs — and then shows the opposite, 2>&1, merging both into the same file so both messages land together, which is what you'd want when debugging and don't want to check two files. The /dev/null example shows how to silence one specific line's output without affecting the rest of the script's normal output around it. Finally, the here-document feeds a fixed three-line message into cat's stdin without a separate template file, and the here-string reads a single value, "hello-there", directly into the word variable via read -r — a quick way to feed one value into a command that expects to read from stdin rather than take an argument.

Try the working example

bash
#!/bin/bash
echo "Piping ls-like data through wc:"
printf "apple\nbanana\ncherry\n" | wc -l

echo ""
echo "Chaining grep and sort in a pipeline:"
printf "banana\napple\ncherry\n" | grep -v banana | sort

echo ""
echo "Redirecting stdout to a file, then reading it back:"
out_file=$(mktemp)
echo "saved output" > "$out_file"
cat "$out_file"

echo ""
echo "Appending more output to the same file:"
echo "second line" >> "$out_file"
cat "$out_file"

echo ""
echo "Redirecting stderr separately from stdout:"
{ echo "this is stdout"; echo "this is stderr" >&2; } 1>"$out_file" 2>"$out_file.err"
echo "stdout file contains:"
cat "$out_file"
echo "stderr file contains:"
cat "$out_file.err"

echo ""
echo "Discarding output with /dev/null:"
echo "you will not see this" > /dev/null
echo "but this line still prints"

echo ""
echo "Combining stdout and stderr with 2>&1:"
{ echo "normal message"; echo "error message" >&2; } > "$out_file" 2>&1
cat "$out_file"

echo ""
echo "Here-document: sending multi-line input to cat"
cat <<EOF
Line one
Line two
Line three
EOF

echo ""
echo "Here-string: sending a single value to a command"
read -r word <<< "hello-there"
echo "Read from here-string: $word"

rm -f "$out_file" "$out_file.err"
You should see
Running this script prints:

Piping ls-like data through wc:
3

Chaining grep and sort in a pipeline:
apple
cherry

Redirecting stdout to a file, then reading it back:
saved output

Appending more output to the same file:
saved output
second line

Redirecting stderr separately from stdout:
stdout file contains:
this is stdout
stderr file contains:
this is stderr

Discarding output with /dev/null:
but this line still prints

Combining stdout and stderr with 2>&1:
normal message
error message

Here-document: sending multi-line input to cat
Line one
Line two
Line three

Here-string: sending a single value to a command
Read from here-string: hello-there

5-minute try-it

Write a script that pipes the output of a small list of numbers through grep to keep only even-looking ones (hint: match a pattern), redirects that filtered result to a file, and separately uses a here-document to print a short multi-line message to the terminal.

One important caution

Writing command > file 2>&1 in the wrong order as command 2>&1 > file, which sends stderr to the terminal instead of the file because 2>&1 is evaluated before stdout has been redirected

Using > instead of >> when the intent was to append, which silently truncates and overwrites the file's previous contents

GNU Bash Manual: RedirectionsBash / Shell Scripting

Easy traps

  • Writing command > file 2>&1 in the wrong order as command 2>&1 > file, which sends stderr to the terminal instead of the file because 2>&1 is evaluated before stdout has been redirected
  • Using > instead of >> when the intent was to append, which silently truncates and overwrites the file's previous contents
  • Validate sample code in a local or test environment before applying it to a production system.

Exercise

Write a script that pipes the output of a small list of numbers through grep to keep only even-looking ones (hint: match a pattern), redirects that filtered result to a file, and separately uses a here-document to print a short multi-line message to the terminal.

You'll know it worked when: Running this script prints: Piping ls-like data through wc: 3 Chaining grep and sort in a pipeline: apple cherry Redirecting stdout to a file, then reading it back: saved output Appending more output to the same file: saved output second line Redirecting stderr separately from stdout: stdout file contains: this is stdout stderr file contains: this is stderr Discarding output with /dev/null: but this line still prints Combining stdout and stderr with 2>&1: normal message error message Here-document: sending multi-line input to cat Line one Line two Line three Here-string: sending a single value to a command Read from here-string: hello-there

Pipes, Redirection, and Here-Documents | Thuta Learning