Chapter 05Lesson 05~65 minutes

Introduction to sed, awk, and Command Pipelines

The Linux text toolbox becomes an operational language when filters are composed deliberately. This lesson introduces sed and awk, then shows how to build pipelines whose data flow and failure behavior remain understandable.

Intermediatesed and awkReliable pipelines

Learning objectives

By the end of this lesson

  • Use sed addresses, substitutions, deletions, and explicit printing.
  • Use awk records, fields, patterns, actions, variables, and aggregation.
  • Explain how a Bash pipeline connects process streams.
  • Detect failures with PIPESTATUS and set -o pipefail.
  • Build a deployment-health report from structured text and verify every stage.

1. A pipeline is a graph of concurrent processes

In A | B | C, the shell connects standard output from each command to standard input of the next. The processes normally run concurrently. Standard error is not piped unless explicitly redirected, and each process has its own exit status.

Data and status in a command pipeline
flowchart TD
  I["Input files or producer"] --> S["sed filters or rewrites records"]
  S --> A["awk selects fields and aggregates"]
  A --> O["sort, report file, or terminal"]
  S -. "exit status" .-> P["Bash PIPESTATUS and pipefail"]
  A -. "exit status" .-> P
  O -. "exit status" .-> P
Readable pipelines are staged programs

When a pipeline becomes difficult to explain, save intermediate output, name the stages, or move the logic into a tested script. Brevity is not reliability.

2. sed applies an editing program to a stream

sed reads one record at a time into a pattern space, executes commands, and normally prints the result. The -n option suppresses automatic printing so that p can select exactly what appears.

log="$HOME/devops-academy/linux/chapter05/lesson05/deployments.tsv"

# Print records 2 through 5 only.
sed -n '2,5p' -- "$log"

# Print records containing a literal status token.
sed -n '/status=FAILED/p' -- "$log"

# Replace the first occurrence on each line; add g for all occurrences.
sed 's/environment=staging/environment=stage/' -- "$log"

# Remove blank lines and comment lines from a simple configuration stream.
sed -e '/^[[:space:]]*$/d' -e '/^[[:space:]]*#/d' -- app.conf

Without -n, combining automatic output with an explicit p command prints selected lines twice. Test transformations without -i first. In-place editing syntax and backup behavior differ among sed implementations, so production scripts should document their portability target.

Addresses and commands

FormMeaningExample
NpPrint record Nsed -n '10p'
M,NpPrint a rangesed -n '5,12p'
/RE/pPrint matching recordssed -n '/ERROR/p'
s/OLD/NEW/gSubstitute matchessed 's/foo/bar/g'
/RE/dDelete matching recordssed '/^#/d'

3. awk is a pattern-action language for records and fields

An awk program consists of rules such as PATTERN { ACTION }. Input is split into records, normally lines, and fields, normally runs of whitespace. $0 is the complete record; $1, $2, and so on are fields; NF is the number of fields; and NR is the cumulative record number.

# Tab-separated input: print service and status fields.
awk -F '\t' '{ print $2, $3 }' -- "$log"

# Select records and format a clear result.
awk -F '\t' '$3 == "FAILED" { printf "%s service=%s duration=%ss\n", $1, $2, $4 }' -- "$log"

# Aggregate counts and averages per service.
awk -F '\t' '
  { count[$2]++; total[$2] += $4 }
  END {
    for (service in count) {
      printf "%s\tcount=%d\tavg_seconds=%.2f\n", service, count[service], total[service] / count[service]
    }
  }
' -- "$log" | LC_ALL=C sort

Use BEGIN for initialization before input and END for final reports. Pass shell values with -v name="$value" rather than constructing program text through unsafe string interpolation.

threshold=120
awk -F '\t' -v limit="$threshold" '
  $4 + 0 > limit { print $1, $2, $4 }
' -- "$log"

4. Make pipeline failure visible

By default, Bash reports a pipeline’s status as the status of its final command. An earlier stage can fail while the final consumer exits successfully. set -o pipefail makes a pipeline fail when any stage fails, using the rightmost non-zero status.

set -o pipefail

if sed -n '/status=/p' -- "$log" \
  | awk -F '\t' '$3 == "FAILED" { print $2 }' \
  | LC_ALL=C sort -u \
  > failed-services.txt; then
  printf 'Report written: %s\n' "$PWD/failed-services.txt"
else
  status=$?
  printf 'Pipeline failed with status %d\n' "$status" >&2
  exit "$status"
fi

Immediately after a pipeline, Bash’s PIPESTATUS array contains each stage’s status. Capture it before another command overwrites it.

sed -n '/status=/p' -- "$log" | awk -F '\t' '{ print $2 }' | sort -u
statuses=("${PIPESTATUS[@]}")
printf 'sed=%s awk=%s sort=%s\n' "${statuses[0]}" "${statuses[1]}" "${statuses[2]}"
Early consumers

Commands such as head or grep -q may exit after obtaining enough input. The producer can then receive a broken-pipe signal. Interpret this carefully when pipefail is enabled.

5. Design pipelines as observable stages

01Bound input

Choose explicit files, roots, timestamps, or record limits.

02Preserve evidence

Keep source filenames, line numbers, and standard-error diagnostics when they matter.

03Normalize once

Convert delimiters or case deliberately and document the assumption.

04Validate intermediate data

Count records, inspect samples, and check expected fields before aggregation.

05Write atomically

Create a temporary output, verify it, then move it into place.

6. Hands-on lab: build a deployment-health report

lab="$HOME/devops-academy/linux/chapter05/lesson05"
mkdir -p -- "$lab"
log="$lab/deployments.tsv"
report="$lab/health-report.txt"
tmp=$(mktemp "$lab/.health-report.XXXXXX")
trap 'rm -f -- "$tmp"' EXIT

cat > "$log" <<'EOF'
2026-08-04T12:00:00Z	orders-api	SUCCESS	82
2026-08-04T12:05:00Z	payments-api	FAILED	145
2026-08-04T12:10:00Z	orders-api	SUCCESS	75
2026-08-04T12:15:00Z	catalog-api	SUCCESS	61
2026-08-04T12:20:00Z	payments-api	FAILED	132
2026-08-04T12:25:00Z	catalog-api	SUCCESS	58
EOF

set -o pipefail
{
  printf '%s\n' 'Deployment health report'
  printf 'Generated: %s\n\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')"

  printf '%s\n' 'Failures by service:'
  awk -F '\t' '$3 == "FAILED" { failures[$2]++ } END { for (s in failures) print failures[s], s }' -- "$log" \
    | sort -nr

  printf '%s\n' '\nAverage duration by service:'
  awk -F '\t' '{ count[$2]++; total[$2]+=$4 } END { for (s in count) printf "%s %.1f seconds\n", s, total[s]/count[s] }' -- "$log" \
    | LC_ALL=C sort

  printf '%s\n' '\nSlow deployments over 120 seconds:'
  awk -F '\t' '$4 + 0 > 120 { printf "%s %s %s seconds\n", $1, $2, $4 }' -- "$log"
} > "$tmp"

[[ -s $tmp ]]
grep -q -F 'payments-api' -- "$tmp"
mv -- "$tmp" "$report"
trap - EXIT
cat -- "$report"

Verification checklist

7. Know when to stop extending the one-liner

sed is excellent for line-oriented selection and substitution. awk is excellent for field-aware calculations and reports. Move to jq for JSON, a YAML processor for YAML, a CSV parser for quoted CSV, or Python/another language when you need nested structures, robust error objects, complex tests, reusable modules, or maintainable domain logic.

Do not parse security-sensitive formats approximately

An apparently simple delimiter split can misread escaping or quoting and produce unsafe decisions. Use a parser that implements the format grammar.

8. Common mistakes and stronger habits

Editing in place before previewing

Run sed without -i, compare output, keep a backup, and document implementation-specific behavior.

Interpolating shell data into awk source

Use awk -v name="$value" so data remains data rather than executable program text.

Checking only the last pipeline stage

Enable pipefail or inspect PIPESTATUS when every stage must succeed.

Hiding standard error

Diagnostics reveal missing files, denied paths, and malformed input. Capture and report them rather than discarding them blindly.

9. Knowledge check

Question 1. Why can sed -n '/ERROR/p' be clearer than sed '/ERROR/p'?

Question 2. What do $0, $1, NF, and NR mean in awk?

Question 3. What problem does Bash set -o pipefail address?

10. Chapter summary

Chapter 5 established a complete text-processing workflow: inspect bounded text, select content with grep, find filesystem objects safely, transform records with focused core utilities, and use sed and awk inside observable pipelines. The governing principles are explicit input boundaries, quoted patterns, preserved evidence, format-aware parsing, verified intermediate states, and visible failures.

Next chapter

Permissions, Ownership, and Access Control

Chapter 6 begins with the Linux permission decision model and the meaning of read, write, and execute on files and directories.

11. Further reading

  • GNU sed manual — addresses, commands, substitution, hold space, and portability options.
  • GNU Awk User’s Guide — records, fields, patterns, actions, arrays, and numeric processing.
  • GNU Bash Reference Manual — pipelines, PIPESTATUS, pipefail, redirection, and traps.
  • GNU Coreutils and Grep manuals — composable filters and sorting behavior.
  • POSIX specifications for sed, awk, shell pipelines, and text files.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.