Anatomy of an AWK file
Awk is a powerful domain-specific language designed for text processing and data extraction, structured around a data-driven pattern-action framework.
File extensions: .awk
Every part of the example below is labelled and explained. This page is one of 55 annotated tours on AnatomyOf, a free, open-source project by LunarWerx Studios.
What is inside an AWK file
Shebang
Specifies the interpreter path (optional, for executable scripts).
The shebang (#!) must be the very first bytes of the file. On Unix-like systems the kernel reads it to pick the interpreter, so #!/usr/bin/awk -f hands the rest of the file to awk as a -f script when it is invoked directly, e.g. ./report.awk after chmod +x. It is entirely optional when you instead run awk -f report.awk data.txt, and it is skipped over as an ordinary comment if the interpreter is invoked explicitly. AWK predates most of the languages that borrowed its shebang convention, having shipped with Unix since 1977. It was extracting fields out of text files before "data engineering" wa
Comment
Single-line comments, ignored by Awk.
A # starts a comment that runs to the end of the line; there is no block-comment syntax, so every explanatory line needs its own #. Comments can trail real code on the same line, which is the idiomatic place to explain a terse one-liner before someone (often you, in six months) has to reverse-engineer it. Because classic AWK programs are prized for fitting on one line at a shell prompt, comments are also where most of the language's actual documentation ends up living, since the code itself is optimized for brevity over readability.
BEGIN block
Executed once before any input is read. Used for initialization.
A BEGIN { ... } block runs exactly once, before AWK reads the first line of input, before the field separator is even applied to anything. It is the natural place to set up variables like counters, print a report header, or reconfigure built-ins such as FS. A program may have multiple BEGIN blocks; AWK concatenates them in the order they appear, as if they were one block. If a program consists of only a BEGIN block, AWK never opens the input file at all, which is a handy trick for using awk as a plain calculator.
Print statement
Outputs text or variable values.
print writes its comma-separated arguments to standard output, joined by the value of OFS (a single space by default) and terminated by ORS, the output record separator, a newline by default. Arguments are concatenated positionally: print "Total: " total glues a string literal directly to a variable with no operator, since adjacency itself means string concatenation in AWK. For anything fancier than default spacing, printf gives C-style format control (printf "%-10s %5d\n", name, count) without the automatic separators print adds. Both write to stdout by default but can be redirected with >, >
Built-in variables
Special variables like FS (Field Separator), NR (Number of Records).
AWK maintains a set of built-in variables that update automatically as it reads input: NR is the total record count seen so far, NF is the number of fields in the current record, and FS/OFS control how fields are split on input and joined on output (FS = "," switches from the default whitespace-splitting to CSV-style parsing). FILENAME and RS (record separator) round out the most commonly tuned ones. Because these are ordinary global variables rather than read-only constants, a program can reassign FS mid-run (for instance after a BEGIN block, or partway through processing a file whose format
Pattern (condition)
Controls if the action block is executed. If empty, action runs for every record.
AWK's core structure is pattern { action }: for every input record, each pattern is tested, and its action runs only if the pattern matches. A pattern can be a comparison like $1 == "data", a regular expression like /error/ (implicitly tested against the whole record, $0), a range /start/,/end/, or omitted entirely: an empty pattern matches every record, which is how { print } becomes a one-line cat replacement. The special patterns BEGIN and END are the only ones not tied to a record; every other pattern is re-evaluated once per line of input, in the order the pattern-action pairs appear in t
Action (block)
Commands to execute when the pattern is matched.
The { ... } following a pattern is a block of statements executed once per matching record: assignments, print/printf, control flow, or calls to user-defined functions. Statements are typically separated by newlines or semicolons, and the block shares AWK's implicit global scope, so a variable like total accumulates naturally across every record that matches. If a pattern has no action at all, AWK assumes { print } (printing the whole matched record verbatim) which is why grep-like one-liners such as awk '/error/' need no braces to work.
Field access ($N)
Accesses fields in the current record ($0 is the whole record, $1 is first field, etc.).
Every input record is automatically split into fields on FS, addressable as $1, $2, ... $NF, while $0 refers to the entire, unsplit record. Fields can be reassigned ($2 = "redacted"), which rebuilds $0 by rejoining every field with OFS; assigning past NF (e.g. $(NF+2) = "x") extends the record with empty fields in between. Field numbers need not be literals ($NF is the last field and $(i+1) computes an index at runtime) which lets a single action generalize across records with a varying number of columns instead of hardcoding positions.
END block
Executed once after all input is read. Used for finalization and reporting.
An END { ... } block runs exactly once, after the last input record has been processed, making it the natural place for summary output like totals, averages, or a closing banner. Variables set during the main pattern-action pairs (like an accumulator built up across every matching record) are still in scope here, since AWK variables are global by default. Crucially, END still has access to the final values of built-ins like NR, so print "Records Processed: " NR inside END reports exactly how many records the whole run consumed, even though no new record triggers it.
Official AWK site · All languages on AnatomyOf
The interactive tour needs JavaScript. Enable it to hover a callout and trace it into the code.