I transformed text non-interactively with sed substitutions for find-replace and awk for field-based reporting and arithmetic. These tools edited config files in place and produced column summaries from logs without ever opening an editor.

Objective & Context

sed and awk are the scripting backbone of text automation. This lab uses sed for line-oriented edits and awk's record/field model for computation, the manual engine behind config templating and log reporting.

Learning Objectives

  • Perform line-oriented substitutions with sed, including in-place edits with backups.
  • Address specific lines and ranges in sed (line numbers, patterns).
  • Use awk's record and field model (NR, NF, $1..$NF) on delimited data.
  • Aggregate columns with associative arrays and END blocks.
  • Write conditional field reports that filter and reformat log lines.

Environment & Prerequisites

Prerequisites

  • Linux with GNU sed and gawk (preinstalled on virtually all distributions).
  • A config file to edit (a copy of sshd_config works well) and a delimited log or CSV.
  • Regex familiarity from the grep lab (sed patterns are regexes).
  • A backup mindset: sed -i edits are immediate.

Step-by-Step Execution

1. In-place substitution with sed

sudo sed -i.bak 's/^#Port 22/Port 2222/' /etc/ssh/sshd_config

Expected output:

(no output on success; sshd_config.bak created)
$ sudo grep "^Port" /etc/ssh/sshd_config
Port 2222

What this teaches: The s/// command substitutes the first match per line; -i.bak edits in place while keeping a backup; ^ anchors to line start so commented variants elsewhere are untouched. Editing /etc/ssh/sshd_config requires root, hence sudo; after any real sshd_config change, validate with sudo sshd -t and reload the daemon.

2. Sum a column with awk

awk -F, '{sum+=$3} END{printf "total: %.2f\n", sum}' sales.csv

Expected output:

total: 18423.50

What this teaches: awk splits each line into $1..$NF on the -F delimiter; the bare {sum+=$3} block runs per record while END runs once after, making one-pass aggregation trivial.

3. Conditional field report

awk '$9 >= 500 {print $1, $9}' access.log

Expected output:

203.0.113.45 503
198.51.100.7 500

What this teaches: The pattern $9 >= 500 filters records before the action runs, so awk replaces a grep-plus-cut pipeline with a single precise pass over the log. Field numbers depend on the log format: $9 is the status only in the combined log format, where the quoted request occupies $6 through $8; in the common format without a timezone field the status is $8. When formats vary, anchor from the end with $(NF-1) instead of hardcoding positions.

How It Works

sed is a streaming editor: it reads one line at a time into the pattern space, applies your script, prints the result, and moves on. Because it never loads the whole file, it edits gigabyte logs with constant memory. Addresses (line numbers, /regex/, or ranges like 10,20) select which lines each command touches, and s/// performs the substitution with & referencing the whole match in the replacement.

awk upgrades the model from lines to records and fields. Each input line is a record (NR counts them); splitting on FS yields fields $1 through $NF. A program is pattern-action pairs: the pattern filters, the action computes. Associative arrays keyed by field values make counting and summing by category a few lines long, which is why awk remains the fastest way to summarize columnar data.

Together they cover the two text-automation shapes: sed for line-oriented transformation (comment toggles, config templating) and awk for field-oriented computation (reports, filters). Knowing which shape your problem is picks the tool before you write a character.

Validation & Testing

Confirm sed created a .bak backup and changed only the intended line, and that awk's totals match a manual sum. Pass criteria: targeted in-place edit with backup, correct field math, and accurate conditional filtering.

Troubleshooting

SymptomLikely causeFix
sed -i destroyed the file with no backup-i was used without an extension argumentAlways use -i.bak (or copy first); GNU sed requires the habit, not the flag
Replacement contains & and it duplicated the match& in the replacement means the whole matchEscape it as \& when you want a literal ampersand
awk prints empty fieldsThe field separator does not match the real delimiterCheck with cat -A, then set -F correctly (e.g. -F'[ \t]+' for runs of whitespace)
Slashes in the pattern clash with s/// delimitersThe pattern itself contains /Use an alternate delimiter: s|old|new| or s#old#new#
Pattern with parentheses did nothing in sedBRE is default; ( ) are literal without backslashesUse sed -E for extended regex, matching grep -E habits
In-place edit on a symlink replaced the linkBy default sed -i breaks the symlink, replacing it with a regular file, so the link target is not modified (per the GNU sed manual)Add --follow-symlinks to edit through the link and preserve it, or edit the real path
Advanced: Troubleshooting
  • sed changed too much: anchor the pattern; unanchored matches hit every line.
  • No in-place backup: use -i.bak to keep the original.
  • awk wrong field: set the field separator with -F to match the data.

Key Results

  • Edited config files in place with safe backups and anchored patterns.
  • Computed column totals and reports directly from delimited data.
  • Filtered records by field conditions without a full script.
  • Replaced manual editing for repeatable text transforms.

Key Takeaways

  • sed edits streams line by line with constant memory; always keep -i.bak backups.
  • Addresses select lines; s/// transforms them; & recalls the match.
  • awk thinks in records and fields, ideal for column math and conditional reports.
  • Pattern-action pairs let awk filter and compute in one pass.
  • Pick sed for line shapes, awk for field shapes.

Practice Challenges

Challenge 1: Config toggle script

Goal: write a sed one-liner that comments out every active Port line and uncomments Port 2222 in an sshd_config copy, idempotently.

Hint: two -e expressions with ^ anchors.

Challenge 2: Bandwidth report

Goal: from an access log, use awk to print total bytes served per status-code class (2xx, 4xx, 5xx).

Hint: sum $10 into an array keyed by substr($9,1,1), then print in END.