awk Cheatsheet

Built-in Variables

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

The full table

Every one of these is a plain global you can read and, unless noted, assign.

VariableDefaultMeaning
NR0records read so far, across every input file
NF—number of fields in the current record
FNR0record number within the current file
FS" "input field separator (a string, or a regex if longer than 1 char)
OFS" "output field separator, used by print a, b and record rebuilds
RS"\n"input record separator ("" means paragraph mode)
ORS"\n"output record separator, appended by print
FILENAME""name of the file being read, empty in BEGIN
SUBSEP"\034"key joiner for a[i,j] subscripts
RSTART0start position of the last match(), 0 if it failed
RLENGTH-1length of the last match(), -1 if it failed
CONVFMT"%.6g"format used when a number becomes a string
OFMT"%.6g"format used when print outputs a number
ARGC / ARGV—operand count and array, ARGV[0] is "awk"
ENVIRON—the process environment, ENVIRON["HOME"]

CONVFMT vs OFMT

Two different formats for two different moments, and mixing them up is a classic source of "why did my number lose digits".

# OFMT applies when print writes a number
awk 'BEGIN{ OFMT="%.2f"; print 3.14159 }'          # 3.14
# CONVFMT applies when a number is concatenated into a string
awk 'BEGIN{ CONVFMT="%.2f"; x=3.14159; print x "" }' # 3.14

- Integers bypass both. awk 'BEGIN{OFMT="%.2f"; print 100}' prints 100. - printf ignores both, its own format string wins. Use printf when the exact digits matter.

Separator variables in practice

# comma in, tab out
awk 'BEGIN{ FS=","; OFS="\t" } { $1=$1; print }' data.csv

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

# paragraph mode: blank-line-separated records
awk 'BEGIN{ RS=""; FS="\n" } { print NR": "$1 }' notes.txt

Assigning FS in a rule affects the next record. Assigning OFS or ORS takes effect immediately, but OFS only shows up once something rebuilds $0.

RSTART and RLENGTH

match(s, re) returns the start position and also sets these two, which is how you extract a substring by regex in POSIX awk.

printf 'id=4711;\n' |
awk '{ if (match($0, /[0-9]+/)) print substr($0, RSTART, RLENGTH) }'
# 4711

On a failed match RSTART is 0 and RLENGTH is -1, so guard with the return value rather than testing RSTART > 0 after the fact.

ARGV, ARGC, and ENVIRON

ARGV holds the operands, not the options. You can edit it in BEGIN to add or drop files before any reading happens.

# list what awk thinks its inputs are
awk 'BEGIN{ for (i=0; i<ARGC; i++) print i, ARGV[i] }' a.txt b.txt
# 0 awk
# 1 a.txt
# 2 b.txt

# read an env var without -v
HOME_DIR=$HOME awk 'BEGIN{ print ENVIRON["HOME_DIR"] }'

Deleting an element of ARGV (or setting it to "") makes awk skip that file. ENVIRON is POSIX and works in macOS awk, gawk, and mawk.

gawk-only variables

Do not reach for these in a script that has to run on macOS or a BSD.

VariableWhat it does
RTthe text that actually matched RS on this record
IGNORECASEnon-zero makes every regex and string compare case-blind
FIELDWIDTHSfixed-width parsing instead of FS
FPATdefine fields by what they are, the sane CSV route
PROCINFOpid, uid, sorted_in, and more. Absent, not an error, on macOS awk
ERRNOmessage from a failed getline or close
BINMODE / LINT / TEXTDOMAINI/O mode, warnings, i18n
# gawk only: quoted CSV fields, the thing plain FS="," cannot do
gawk -v FPAT='([^,]*)|("[^"]*")' '{ print NF, $2 }' quoted.csv

# gawk only: deterministic iteration order
gawk 'BEGIN{ PROCINFO["sorted_in"]="@ind_str_asc" }
      { c[$1]++ } END{ for (k in c) print k, c[k] }' data.txt

macOS awk silently treats IGNORECASE as an ordinary unused variable, so the script runs and quietly does the wrong thing. That is worse than an error, test your awk before relying on it.