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

FormMeaning
k in atrue if key k exists, does not create it
(i, j) in amembership test for a multidimensional key
delete a[k]remove one element
delete aremove 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 argumentSplits on
omittedthe 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

sort on the outside beats reimplementing sorting inside awk. gawk has asort and asorti, macOS awk and mawk have neither.