awk Cheatsheet
Control Flow and User Functions
Use this awk reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Statements
Same shapes as C, with no types and no declarations.
if (cond) stmt; else stmt while (cond) stmt do stmt while (cond) for (init; cond; incr) stmt for (key in array) stmt break # leave the innermost loop continue # next iteration next # next input record nextfile # next input file exit [expr] # jump to END, then quit return [expr] # only inside a function
awk '{
for (i = 1; i <= NF; i++)
if ($i ~ /^-/) { print "flag:", $i; continue }
}' args.txt
awk 'BEGIN{ i = 0; do { print i } while (++i < 3) }'- Braces are optional around a single statement, required around several.
- ; separates statements on one line, a newline does the same. A statement may
break across lines after , { && || do or else.
- break or continue outside a loop is an error, not a silent next.
- There is no switch in POSIX awk. gawk has one, macOS awk and mawk do not, so
chain else if.
Defining a function
function name(param, param) { ... return value }
awk ' function max(a, b) { return a > b ? a : b } function pad(s, n) { while (length(s) < n) s = s " "; return s } { print pad($1, 12), max($2, $3) } ' data.txt
- At a call site the name and the ( must touch. max (1, 2) is parsed as
concatenation and is a syntax error. In the definition a space is tolerated by both
macOS awk and gawk, but POSIX forbids it, so do not write it.
- A function may be defined anywhere in the program, before or after its callers,
and -f files are concatenated so definitions can live in a library file.
- A function with no return returns the empty string, which is also 0.
- Recursion works.
awk 'function fact(n) { return n <= 1 ? 1 : n * fact(n - 1) } BEGIN { print fact(10) }' # 3628800
Scope, and the extra-parameter idiom
awk has no local variables. Every variable is global except a function's declared parameters. The convention is to declare extras you never pass, padded with whitespace so readers can see they are locals.
function join(arr, n, sep, i, out) { # i and out are locals out = arr[1] for (i = 2; i <= n; i++) out = out sep arr[i] return out }
awk ' function trim(s) { sub(/^[ \t]+/, "", s); sub(/[ \t]+$/, "", s); return s } function count_words(line, n, parts) { # n and parts are locals n = split(line, parts, /[ \t]+/) return n } { print count_words(trim($0)) } ' notes.txt
- Scalars are passed by value, arrays are passed by reference. That is the
only way to return a collection.
- Calling with fewer arguments than parameters is legal, the missing ones start
uninitialized. That is what makes the locals idiom work.
- Forget the padding and you will overwrite a global i from your main loop, a bug
that only shows up on large inputs.
# array out-parameter, since arrays are by reference awk ' function tally(line, out, i, n, w) { n = split(line, w, /[ \t]+/) for (i = 1; i <= n; i++) out[w[i]]++ } { tally($0, counts) } END { for (k in counts) print counts[k], k } ' notes.txt
Reusable function files
cat > lib.awk <<'EOF' function commify(n, s, out) { s = sprintf("%d", n) while (length(s) > 3) { out = "," substr(s, length(s) - 2) out s = substr(s, 1, length(s) - 3) } return s out } EOF awk -f lib.awk -f main.awk data.txt
-f is repeatable and the files are concatenated in order, so a library plus a
program is the normal way to share helpers. -f - reads the program from stdin.
Record-level flow inside functions
next and nextfile are not allowed inside a function body in POSIX awk, and
gawk warns about them. exit is fine and still runs END.
# do this instead of next-in-a-function: return a flag awk ' function skip(line) { return line ~ /^#/ || line == "" } skip($0) { next } { print NR": "$0 } ' config.ini
| Statement | In a rule | In a function | In BEGIN/END |
|---|---|---|---|
next | ✓ | ✗ | ✗ |
nextfile | ✓ | ✗ | ✗ |
exit | ✓ | ✓ | ✓ |
return | ✗ | ✓ | ✗ |
getline | ✓ | ✓ | ✓ |