Variables, Loops & Fields
Local variables
In AWK, every variable is global, and the only way to get a local is the "extra function parameter" idiom.
zawk adds local:
{
local total = 0, seen[]
for (i = 1; i <= NF; i++) {
if ($i in seen) continue
seen[$i]
total += $i
}
print total
}
local a = exprdeclaresafor the rest of the rule (or function body), including nested blocks. It shadows a globala, which other rules still see.- A local is uninitialized again on each run of the rule:
{ local n; n++; print n }prints1for every record. local arr[]declares an empty array. Several can be declared at once:local i, s = "", seen[].local x = x + 1reads the outerx.- In a function, locals are new on each call, like the extra-parameter idiom.
- Special variables (
NR,FS,SUBSEP...) and function names cannot be local.
Key-value iteration
Like Python's for k, v in d.items(): for (k, v in arr) body is the same as
for (k in arr) { v = arr[k]; body }.
zawk '{ c[$1]++ } END { for (k, v in c) print k, v }' words.txt
On an array made by split, it works like Python's enumerate:
BEGIN {
n = split("red green blue", colors)
for (i, name in colors) print i, name
}
arr must be an array variable: for (k, v in f()) is a syntax error, assign the result first
(a = f(); for (k, v in a)). The classic for (k in f()) does accept a function call.
The iteration order is unspecified unless PROCINFO["sorted_in"] is set to one of gawk's predefined orders
("@ind_str_asc", "@val_num_desc", ...):
END {
PROCINFO["sorted_in"] = "@val_num_desc"
for (word, n in count) print n, word
}
Range loops
.. (exclusive) and ..= (inclusive) are range operators in a for (i in start..end) header:
$ zawk 'BEGIN { for (i in 1..4) printf "%d ", i; print ""; for (i in 1..=4) printf "%d ", i; print "" }'
1 2 3
1 2 3 4
Range bounds are integers. Outside a for header, 1..3 keeps its AWK meaning (1. concatenated with .3).
Negative field indexes
Like Python's xs[-1]: $(-k) is $(NF + 1 - k), so $(-1) is $NF and $(-2) is $(NF-1).
$ echo "a b c" | zawk '{ print $(-1), $(-2) }'
c b
- Write the index in parentheses:
$-1is a syntax error. - Reading before the first field gives
""; assigning there is a fatal error. - Only a literal index counts from the end. A negative index computed at runtime (e.g.
$(NF-2)on a one-field record) is a fatal error, as in gawk, instead of silently reading another field.
assert
assert(cond, msg) fails fast: when cond is false, msg is printed to stderr and zawk exits at once with
code 2. Unlike exit 2, the END block is not run.
zawk -i csv '{ assert(NF == 5, f"line {NR}: expect 5 fields, got {NF}") } { ... }' data.csv
Field list shorthand
A command-line program that is only a comma-separated list of two or more fields prints them:
zawk '$1,$3' file # zawk '{ print $1, $3 }'
zawk '/ERROR/' app.log # print matching lines
A single field such as zawk '$2' keeps the standard AWK meaning: print records whose $2 is non-empty and
non-zero. Use --posix to disable all command-line sugar.
Functions returning arrays
User-defined and stdlib functions can return arrays, and a call can be indexed directly:
function keys_of(arr, k, out, n) {
for (k in arr) out[++n] = k
return out
}
{ print url($1)["host"], pairs(url($1)["query"], "&")["id"] }
Multidimensional arrays
POSIX-style multidimensional arrays are supported: a[i, j], (i, j) in a, delete a[i, j] and SUBSEP.
True arrays of arrays (a[i][j]) are not.
Includes
@include "lib" (or --include lib on the command line) loads an AWK library file once, searched in AWKPATH
(default .:/usr/local/share/awk), trying lib then lib.awk.
Running Markdown
-f accepts a Markdown file and runs its first ```awk (or zawk/gawk) code block, so documentation and
LLM answers are runnable as is:
zawk -f notes.md data.txt
zawk -i csv -H "$(zawk llm -i csv -H demo.csv 'how many adults?' | llm)" demo.csv