awk Cheatsheet
Arrays
Use this awk reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Everything is an associative array
There is one array type. Subscripts are always strings, so a[1] and a["1"]
are the same element, and there is no declaration step.
awk 'BEGIN{
count["apple"] = 3
count["pear"] += 1
total = count["apple"] + count["pear"]
print total # 4
}'- A numeric subscript is converted with CONVFMT, so a[0.1] and a["0.1"] match
but a[1/3] depends on CONVFMT precision. Use integers or explicit strings.
- Arrays cannot be assigned or returned whole. b = a is an error, and a function
can only take an array by reference as a parameter.
in, delete, and accidental creation
| Form | Meaning |
|---|---|
k in a | true if key k exists, does not create it |
(i, j) in a | membership test for a multidimensional key |
delete a[k] | remove one element |
delete a | remove every element (universal, not in POSIX 2008) |
length(a) | element count (gawk, mawk, current macOS awk) |
awk 'BEGIN{
print ("k" in a), length(a) # 0 0, the test created nothing
if (a["k"] == "") ; # merely *referencing* it creates the element
print length(a) # 1
}'That is the trap: if (a[x] == "") grows the array. Use if (!(x in a)) when you
only want to look.
# safe existence check awk 'NR==FNR { keys[$1]; next } ($1 in keys)' allow.txt data.txt
keys[$1] with no value on the right is the idiomatic "add key, value irrelevant".
Iteration is unordered
for (k in a) visits keys in an implementation-defined order that is not
insertion order and not sorted. Never depend on it.
# sort by piping out awk '{ c[$1]++ } END { for (k in c) print c[k], k }' hits.log | sort -rn | head # sort by iterating a numeric index you control awk '{ line[NR] = $0 } END { for (i = 1; i <= NR; i++) print line[i] }' file # gawk only: deterministic traversal gawk 'BEGIN { PROCINFO["sorted_in"] = "@val_num_desc" } { c[$1]++ } END { for (k in c) print c[k], k }' hits.log
PROCINFO is the one gawk extension that fails silently. macOS awk has no
PROCINFO, so the assignment just creates an ordinary array element, and you get
unsorted output with no error at all. Pipe to sort when it has to be portable.
Deleting the current key inside for (k in a) is allowed, adding a key during the
loop is undefined. Build a second array instead.
Multidimensional arrays via SUBSEP
POSIX awk has no real 2-D array. a[i, j] is sugar for a[i SUBSEP j], where
SUBSEP defaults to "\034" (ASCII FS), a byte your data almost never contains.
awk 'BEGIN{
m[1, 2] = "x"
for (k in m) { split(k, p, SUBSEP); print p[1] "/" p[2], m[k] }
# 1/2 x
if ((1, 2) in m) print "present"
}'# a 2-D grid from a table awk '{ for (i = 1; i <= NF; i++) cell[NR, i] = $i } END { print cell[2, 3] }' table.txt
- (1, 2) in m needs the parentheses. Without them awk parses 1, 2 in m as two
expressions, 1 and (2 in m), and prints 1 0 instead of erroring.
- gawk also supports true nested arrays (a[1][2]), which macOS awk and mawk do
not. Stick to SUBSEP for portability.
- If your keys can contain "\034", set SUBSEP to something safer in BEGIN.
split, and building arrays from strings
split(string, array, [sep]) fills array[1..n] and returns n. It clears the
array first.
awk 'BEGIN{ n = split("a:b:c", p, ":"); print n, p[3] }' # 3 c awk 'BEGIN{ n = split("a1b22c", p, /[0-9]+/); print n, p[2] }' # 3 b awk 'BEGIN{ n = split("abc", p, ""); print n, p[2] }' # 3 b awk '{ split($0, f); print f[NF] }' file # default FS
| Third argument | Splits on |
|---|---|
| omitted | the current FS |
":" | that single character |
"[0-9]+" or /re/ | an ERE |
"" | every character (gawk and current macOS awk, not POSIX) |
Common array recipes
# count unique values of column 1 awk '{ c[$1]++ } END { for (k in c) print k, c[k] }' data.txt # sum a value per key awk '{ s[$1] += $2 } END { for (k in s) printf "%s %.2f\n", k, s[k] }' d.txt # collect values per key into a joined string awk '{ g[$1] = ($1 in g ? g[$1] "," $2 : $2) } END { for (k in g) print k": "g[k] }' data.txt # min and max per key awk '{ if (!($1 in lo) || $2 < lo[$1]) lo[$1] = $2 if (!($1 in hi) || $2 > hi[$1]) hi[$1] = $2 } END { for (k in lo) print k, lo[k], hi[k] }' data.txt # invert a lookup awk '{ rev[$2] = $1 } END { print rev["bob"] }' users.txt
sorton the outside beats reimplementing sorting inside awk. gawk hasasortandasorti, macOS awk and mawk have neither.