Writing Criteria
Every guide in this repo is written to the same standard. If you're adding or editing a guide — human or AI — hold it to these.
- Plain words, real ideas. Simple language, never dumbed-down concepts. Explain jargon on first use; collect terms in the glossary.
- No hype. No marketing adjectives, no "revolutionary," no promises about what something will do for the reader.
- Honest about limits. Say what the thing can't do. State uncertainty instead of smoothing it over. Validation notes include what remains unverified.
- No invented numbers. Benchmarks, defaults, and specs are either measured or qualified with "depends on your setup." If it wasn't tested, say so.
- Checkable. Commands are meant to be run, with "Check:" blocks showing what success looks like. Sources are linked, not asserted.
- Respect the reader's setup. Call out Windows/Mac/Linux differences. Don't assume a GPU, a budget, or prior experience.
- Safety isn't skipped. Real risks get stated plainly, not buried.
- Scoped. Each guide says what it covers and points elsewhere for the rest. No guide pretends to be the whole subject.
- Structure over prose. Tables, before/after examples, symptom → fix. Scannable beats essay.
Verification notes for this guide
Standard 3 and 4 applied to this guide,
specifically. The build machine ran Ubuntu
24.04 with GNU grep 3.11, GNU sed
4.9, and mawk 1.3.4 as its awk
(there is no gawk on the build machine),
plus GNU coreutils sort and uniq 9.4.
Every quoted output in the chapters is a
capture from those tools, run against the
shipped specimen files. Working transcripts
are kept with the build
(text-processing-lab/transcripts/).
The lab. Five specimen files in
examples/: app.log (56 lines of
invented server log over three days),
passwd.txt (12 passwd-format accounts),
orders.csv (a header and 14 invented
orders), app.conf (10 lines, one setting
deliberately commented out and replaced),
and messy.txt (15 lines with mixed case,
leading and trailing spaces, duplicates,
and a blank line — the trailing spaces are
load-bearing). Three fixtures are made by
the reader, exactly as the chapters show:
patterns.txt and fix.sed (typed from
the printed contents) and the site/ tree
(a copy of app.log plus a two-line
readme). Three more are made by commands
quoted in chapter 10: bin.dat (a NUL-
containing file from a printf shown in
the chapter), crlf.txt (likewise), and
the scratch.txt/scratch.txt.bak pair
in chapter 5, which is a copy of
messy.txt before and after a real
in-place edit.
Verified by running, per chapter:
- Ch. 1: all three
--versionlines as printed by the build machine (mawk's--versionanswering "mawk 1.3.4 20240123");wc -lover the five specimens;headof three of them;grep -c ERROR(10); the line-10 sed pair; theNR==10awk field print; the CSV item column's first four values. - Ch. 2: the full ERROR listing (10
lines);
-non "login failed" (11 lines);-ccounts for ERROR (10) and "login ok" (7);-imatching a differently-cased pattern;-v nologin(6 lines);-A,-B,-Caround the account-locked line;^2026-10-19count (17);status=ok$(5 lines);^rootandbash$; thelogin/nologinmatch (6 lines) and its-wcounterpart (no output, exit 1);-Fon the config address, and on a pipedecholine whosex/y/zprove the un--Fdots match any character;-lacross three files; per-file-ccounts forpaul(6/1/5). - Ch. 3: the
[0-9]lesson — a two-digit figure refusing a one-digit class (no output, exit 1), then matching with the class doubled; the escaped-dot count (14) and the unescaped count beside it (also 14 on this data, as the chapter says);-E[0-9]+%(3 lines) and the BRE\+spelling of the same;-Ec 'ERROR|WARN'(24); theuser=(paul|katherine)alternation (10 lines);-oPwith\Kand with\d{4}— both work in this build's grep;-ewith two patterns (3 lines);-f patterns.txt(4 lines); recursive search over the madesite/tree, including-rland the--include='*.txt'narrowing; exit codes 0, 1, and 2 captured viaecho $?, including grep's own missing-file message;-qboth ways (silent, exits 0 and 1). - Ch. 4: first-match versus
gon the root line's colons; substitution across all 7 "login ok" lines; pass-through of unmatched lines (head of a whole-file substitution); theiflag over the messy list's three spellings, withgrep -c Applesafterwards proving the file unchanged (1);-nwith line range5,7p; pattern address/ERROR/p; address-plus-substitute/login failed/s/failed/FAILED/p(11 lines); the mixed range1,/ERROR/p(shown by its last three lines); alternate delimiters|…|…|beside its backslash-escaped slash form (identical outputs);dby pattern (/^#/don the config), by pattern with a count (/DEBUG/dleaves 54), and by line range (2,3d). - Ch. 5: two
-eedits in one pass;fix.sedcreated by the quotedprintf,cated, and run with-f(two lines shown by address, 18 LOGIN lines counted); BRE capture groups\([a-z]*\)with\1bracketing usernames on all 7 login-ok lines; the two-group date/time swap (first three lines);&as whole-match ([ERROR]on all 10 error lines);-Egroups rewritingip=toaddress=on the 3 heartbeat lines; in-place editing for real:cpto a scratch file,sed -i.bak 's/ *$//',lsshowing both files,diffreporting exactly the 4 lines that carried trailing spaces (and exiting 1 — differences found, as the chapter explains),cat -Aconfirming the spaces are gone. - Ch. 6:
$1, $3printing;-F:and theBEGIN {FS}form (same table);$NFover the log's first six lines;$1over the whole messy list, blank line included;{print NR, $0}over the config's first four lines; pattern-only awk counted throughwc -l(18 "failed" lines, 10 with$3 == "ERROR"); the uid range test including its trap —nobody(65534) genuinely printed by$3 >= 1000, then excluded by the$3 < 60000refinement, whose 5-line output is also captured; the fullNR>1item column (14 values). - Ch. 7: column sum (59); shipped
revenue accumulated with a field
condition, printed raw (248.66) and
with
printf "%.2f"(248.66); WARN count (14); average (4.21);OFS=" -> "output; theprintfformatted order table;BEGIN/ENDframing lines; per-level counts from an associative array (INFO 30, ERROR 10, WARN 14, DEBUG 2 — quoted in the order mawk'sforloop produced them, as the chapter warns); per-item quantity sums (sprocket 32 of 59);NRversusFNRover two files (68, 12); per-file counts indexed byFILENAME. - Ch. 8:
uniq -con unsorted levels (run-length output, first 8 runs shown);sort | uniq -c(four true totals); the ranked form withsort -rn; UID sort with-t: -k3 -n(nobody last at 65534); quantity sort-t, -k5 -nr, top 3; shell frequency via awk field 7 through the counting pair (nologin 6);sort -uon the messy list removing nothing (15 lines, blank included); the full top-talkers pipeline (198.51.100.23 first at 11); per-day failed logins (4, 5, 2). - Ch. 9: every recipe run as written,
including the config trap —
grep db_hostreturning both the live and the commented line — and both fixes;cat -Aon the messy list; the cleanup pipeline's 8-line result, written tomessy-clean.txtby redirection andcated back; the login-count pipeline (katherine 3, paul 4); the shipped-orders sentence (9 orders, revenue 248.66, average 27.63). - Ch. 10: every symptom reproduced:
grep CRITICALsilence with exit 1; the missing-file message with exit 2; the binary refusal in this build's wording ("grep: bin.dat: binary file matches", exit 0),-con the same file (1), and-aoutput shown throughcat -v(NULs rendered^@); the CRLF file made by the quotedprintf, exposed bycat -A(^M$on both lines),grep 'two$'failing (exit 1), unanchoredgrep twomatching, and thesed 's/\r$//'fix matching; awk's empty$2on the CSV with the default separator (three blank lines, real output) and the same program fixed by-F,; the double-quoted awk program printing whole lines (run in a context with an empty$1, as an interactive shell presents it) beside the single-quoted one printing dates; the&replacement producingandamp;, and\&producing the intended&.
Capture hygiene (declared trims):
long listings are sometimes shown with
head/tail in the command itself —
the trim is part of the quoted command,
never applied silently afterwards; two
chapter 2 and 3 listings state their full
counts in the text (11 login-failed
lines, 10 alternation lines) where the
page shows the first five. The capture
harness's own command echoes escaped
some characters for its bookkeeping
(doubled backslashes in its transcripts);
the chapters quote every command in the
form a reader types, and each was
verified against the capture's output.
Exit-code annotations in the transcripts
(the harness's [exit N] lines) are not
quoted except where the chapter ran
echo $? itself — which is most of the
places the guide discusses a code.
Ordering, stated once: sort
output and awk's for (x in array)
order are the build machine's (its
locale collation; mawk's hash order).
The chapters say both are
implementation weather, not promises:
counts are stable, order is not.
Documented-only (not run), and why:
- BSD and macOS differences:
sed -i ''for in-place editing without a backup, the absence ofgrep -P, and the older phrasing "Binary file … matches" are stated from the tools' documentation and general knowledge, flagged in place. No BSD system was available to the build; the GNU forms they contrast with are all captured. - gawk-specific behaviour is named
(extensions such as
gensub()andBEGINFILEexist) but never used — the build machine has no gawk, and everything taught is the awk common core, run under mawk. - BusyBox versions of the trio (common in containers and embedded systems) accept most of this guide and a few spellings less; named here rather than tested, there being no BusyBox on the build machine.
- The hold space (sed's
h/H/g/G/x) is named and scoped out in chapter 5, not demonstrated — a deliberate scope decision, recorded here so it isn't mistaken for an oversight. - Installation on a reader's machine is described, not performed; the tools were already present.
Specimen discipline, for the record: the
only people in the guide are two specimen
accounts in an invented passwd file; the
only addresses are documentation ranges
and private ranges; the orders, prices,
and log events are invented, and their
totals in the text are the captures' own.
Nothing in the guide was run against a
real system file — the account file is a
specimen, and the chapters say to copy it,
not to aim the commands at /etc/passwd
or a live log until the reader means it.