awk Cheatsheet

Output Formatting

Use this awk reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Format specifiers

SpecPrints
%d %iinteger, truncating the fraction
%o %x %Xoctal, lower and upper hex
%uunsigned decimal
%cone character. A number becomes that character code, a string its first char
%sstring
%e %Escientific, 1.234500e+04
%ffixed point, 6 decimals by default
%g %Gshorter of %e and %f, trailing zeros dropped
%%a literal percent sign
ModifierEffect
%-10sleft justify in width 10
%10sright justify in width 10
%.3fprecision, 3 decimals
%.5struncate a string to 5 characters
%010.3fzero-pad to total width 10
%+dalways show a sign
% dspace where a plus would go
%*dwidth taken from the next argument
awk 'BEGIN{ printf "%5.2f|%-5s|%05d|%x|%e\n", 3.14159, "ab", 42, 255, 12345 }'
#  3.14|ab   |00042|ff|1.234500e+04
awk 'BEGIN{ printf "%*d|\n", 6, 42 }'      #     42|
awk 'BEGIN{ printf "%c%c\n", 72, "int" }'  # Hi
awk 'BEGIN{ printf "100%%\n" }'            # 100%

Too few arguments is a fatal error in both macOS awk and gawk (not enough args in printf). Too many are silently ignored, with no warning, so a shifted format string fails quietly in only one direction.

Aligned tables

# a fixed-width report with a header rule
awk 'BEGIN{ printf "%-12s %8s %6s\n", "NAME", "BYTES", "PCT"
            printf "%-12s %8s %6s\n", "------------", "--------", "------" }
     { printf "%-12.12s %8d %5.1f%%\n", $1, $2, 100 * $2 / 1024 }' sizes.txt
# right-align a numeric column whose width you learn on the fly
awk '{ v[NR]=$2; k[NR]=$1; if (length($2) > w) w = length($2) }
     END { for (i=1;i<=NR;i++) printf "%-10s %*s\n", k[i], w, v[i] }' sizes.txt

When the columns come from the data rather than a format string, column -t is usually less work:

awk 'BEGIN{OFS="\t"} { $1=$1; print }' data.txt | column -t -s $'\t'

Separators: OFS and ORS

# tab-separated output from comma-separated input
awk 'BEGIN{ FS=","; OFS="\t" } { $1=$1; print }' in.csv

# one long comma-joined line
awk 'BEGIN{ ORS="," } { print $1 } END{ printf "\n" }' in.txt

# blank line between records
awk 'BEGIN{ ORS="\n\n" } { print }' in.txt

The $1=$1 is required. OFS is applied when awk rebuilds $0, and printing an untouched record uses the original bytes. Touching any field forces the rebuild.

Number formatting gotchas

awk 'BEGIN{ print 0.1 + 0.2 }'              # 0.3, OFMT hides the float error
awk 'BEGIN{ printf "%.17f\n", 0.1 + 0.2 }'  # 0.30000000000000004
awk 'BEGIN{ print 2^53 + 1 }'               # 9007199254740992, precision lost
awk 'BEGIN{ print 1234567.891 }'            # 1.23457e+06, OFMT is %.6g
awk 'BEGIN{ printf "%.3f\n", 1234567.891 }' # 1234567.891

- awk numbers are C doubles. Integers above 2^53 are not exact, and big IDs read as numbers will silently round. Keep them as strings ($1 ""). - print sends a non-integral number through OFMT (%.6g), which is why 1234567.891 prints as 1.23457e+06. Values that are whole numbers bypass it and print in full. Use printf "%d" or printf "%.15g" when the digits matter. - %d on a value beyond a 64-bit integer is undefined. gawk warns, macOS awk does not. - gawk has --bignum for arbitrary precision. macOS awk and mawk do not.

Redirecting output

FormEffect
print > "f"truncate f on the first write, then append
print >> "f"append, never truncates
print | "cmd"pipe into a shell command
print > "/dev/stderr"stderr (gawk always, macOS awk via the real device)
close("f")flush and release the handle
# split by key, closing handles so you do not run out of descriptors
awk '{ f = "part_" $1 ".txt"; print >> f; open[f]=1 }
     END { for (k in open) close(k) }' data.txt

# sort a section without leaving awk
awk '/^BEGIN/,/^END/ { print | "sort" } END { close("sort") }' file

# warnings to stderr, data to stdout
awk 'NF != 3 { print "bad line " NR > "/dev/stderr"; next } { print $2 }' d.txt

Parenthesize a computed target. print > "out" i ".txt" is a syntax error in macOS awk and is misparsed by gawk. Write print > ("out" i ".txt"), or put the name in a variable first. Two different strings mean two different files, and each stays open until you close() it.