Skip to content

What Text Processing Is

A text file, to the tools in this guide, is a list of lines. Each line is a string of characters ending in an invisible newline, and most lines that mortals meet are secretly a table in disguise: a log line is a date, a time, a level, a component, and a message; a config line is a name, an equals sign, and a value; a CSV row is a list of values with commas between them. Text processing is the craft of working with that structure using three ideas — lines, fields (the pieces a line splits into), and patterns (descriptions of the lines or pieces you want).

The material is everywhere once you look: application and system logs, configuration files, account and inventory lists, data exported as CSV, and the output of other commands, which is just a text file that hasn't landed yet. The questions are always the same few. Which lines mention the failure? How many times did it happen, and on which day? What do the numbers in column five add up to? Who keeps knocking on the door? Three tools, unchanged in their essentials since the 1970s, answer all of them.

The three tools

grep selects lines. You give it a pattern and a file; it prints the lines that match. It does not change anything, and it thinks one line at a time. This morning's question, in its whole form:

$ grep -c ERROR app.log
10

sed edits lines as they stream past — its name is short for stream editor. You give it an editing command; it prints every line with the command applied, and the file itself is untouched unless you explicitly ask otherwise:

$ sed -n '10p' app.log
2026-10-17 09:58:47 ERROR app job import-orders failed reason=timeout
$ sed -n '10p' app.log | sed 's/ERROR/PROBLEM/'
2026-10-17 09:58:47 PROBLEM app job import-orders failed reason=timeout

awk splits lines into fields and computes. Each line arrives as $1, $2, $3 … and you write small pattern–action rules: when a line looks like this, do that with its fields. Line 10 again, asked for its third and fourth fields (the level and the component):

$ awk 'NR==10 {print $3, $4}' app.log
ERROR app

And the same shape reads a column out of a CSV file, skipping its header row:

$ awk -F, 'NR>1 {print $4}' orders.csv | head -4
widget
gadget
sprocket
cable

Select, edit, compute. Most real work is a short pipeline of the three, which is where this guide ends up — but each tool is taught on its own first, because a pipeline is only debuggable one stage at a time.

Have you got them?

All three are standard issue on Linux and macOS and have been for decades. Ask each one its version:

$ grep --version | head -1
grep (GNU grep) 3.11
$ sed --version | head -1
sed (GNU sed) 4.9
$ awk --version | head -1
mawk 1.3.4 20240123

Those captures are the build machine's, and yours may differ in a way that matters more than the numbers: these tools have dialects. GNU grep and GNU sed (Linux) accept options and spellings that the BSD versions on macOS don't, and "awk" is a language with several implementations — gawk, mawk, and the BSD awk among them. This guide was verified on GNU grep 3.11, GNU sed 4.9, and mawk 1.3.4, and it teaches the common core that runs everywhere; wherever a dialect difference bites — and a few do — the chapter stops and says so, and criteria.md lists which claims are documented rather than captured.

The lab

Five specimen files live in examples/. All of them are invented, and every command in the guide runs against them:

File What it is
app.log 56 lines of a small server's log, three days of it — logins, web requests, jobs, disk warnings, errors
passwd.txt 12 account lines in passwd format: name, password field, ids, real name, home, shell — colon-separated
orders.csv 14 orders plus a header row: id, date, customer, item, quantity, price, status
app.conf 10 lines of configuration, including one setting commented out and replaced — a trap for the unwary
messy.txt 15 lines of a shopping list with mixed capitals, stray spaces, duplicates, and a blank line

A first look at three of them:

$ wc -l app.log passwd.txt orders.csv app.conf messy.txt
  56 app.log
  12 passwd.txt
  15 orders.csv
  10 app.conf
  15 messy.txt
 108 total
$ head -4 app.log
2026-10-17 06:00:01 INFO cron job nightly-backup started
2026-10-17 06:04:37 INFO cron job nightly-backup finished status=ok
2026-10-17 07:15:22 INFO auth login ok user=paul ip=192.168.1.10
2026-10-17 07:15:40 INFO http GET /index.html 200 ip=192.168.1.10
$ head -4 passwd.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin

Copy the specimens to a scratch folder and work there — chapter 5 deliberately edits a file in place, and you want the originals pristine:

$ mkdir textlab
$ cp examples/* textlab/
$ cd textlab

(examples/commands.txt is a pocket reference card for the whole guide, and examples/lab-notes.txt describes each specimen; both come along for the ride.)

Check: the three --version commands answer (one may name a different implementation than the captures — that is fine, and the chapters flag where it matters); wc -l reports the five counts above; and grep -c ERROR app.log says 10 in your scratch folder.

Next: grep, the selector — every option a beginner actually needs, on the log's real lines.