Skip to main content

New AWK Syntax

zawk keeps the AWK language: patterns and actions, BEGIN/END, fields, associative arrays, printf, getline, user-defined functions and gawk's switch. On top of it, zawk adds a small set of modern constructs that make everyday scripts shorter and safer. Every addition is designed so that existing AWK programs keep their meaning (the few exceptions are listed in Differences from gawk).

At a glance​

SyntaxExampleLike
f-stringf"user {$1} at line {NR:05d}"Python f-strings
Raw stringr"C:\Program Files", $0 ~ r"\d+\.\d+"Rust raw strings
Default value ??"Hello " name ?? "Guest"C#/JS ??
Default assignment ??=OFS ??= ","JS ??=
try ... elsebody = try read_all(url) else ""Kotlin/Rust ?
!in$1 !in seen { seen[$1]; print }Kotlin !in
match expressionmatch $2 { "error" | "fatal" => 3, /^W/ => 2, _ => 0 }Rust match
switch statementswitch ($1) { case /^a/: ...; break }gawk
local variables{ local total = 0; ... }JS let
Key-value loopfor (k, v in count) print k, vPython items()
Range loopfor (i in 1..=10)Rust ranges
Negative field index$(-1), $(-2)Python xs[-1]
assertassert(NF == 5, f"line {NR}: bad record")many languages
Field list shorthandzawk '$1,$3' filecut
Structured I/Ozawk -i csv -H '{ print $FI["name"] }'xsv, DuckDB

A taste​

#!/usr/bin/env -S zawk -E
# @desc Summarize API latency per endpoint from a JSON Lines log

{
local ms = $FI["latency_ms"] ?? 0
level = match $FI["status"] {
/^2/ => "ok",
/^4/ => "client",
/^5/ => "server",
_ => "unknown"
}
lat[$FI["path"]] += ms
hits[$FI["path"]]++
errors[level]++
}

END {
for (path, total in lat)
print f"{path:<24} {hits[path]:>6} {total / hits[path]:>8.1f} ms"
for (k, v in errors) print k, v > "/dev/stderr"
}
zawk -i jsonl -f latency.awk api.jsonl

Keywords​

local, try and match ... { are new keywords: they can no longer be used as variable or function names. f"..." and r"..." are always string literals, so write f "x" (with a space) to concatenate a variable named f with a string. zawk lint reports these cases (W103).