Toolmingo
Guides10 min read

awk Cheat Sheet: Every Pattern and Function You Need

A complete awk cheat sheet — field splitting, built-in variables, pattern matching, arrays, string functions, BEGIN/END blocks, and real-world one-liners. Copy-ready awk commands.

awk is a text-processing language built for pattern-matching, field extraction, and report generation on structured text. It processes input line-by-line, splits each line into fields, and runs your program against each line that matches a pattern.

Quick reference

Task Command
Print 2nd field awk '{print $2}' file
Print last field awk '{print $NF}' file
Filter by pattern awk '/pattern/' file
Filter by field value awk '$3 > 100' file
Custom delimiter awk -F: '{print $1}' /etc/passwd
Custom output delimiter awk -F, 'BEGIN{OFS="\t"} {print $1,$2}' file
Count matching lines awk '/error/{n++} END{print n}' log
Sum a column awk '{sum+=$2} END{print sum}' file
Print lines 5–10 awk 'NR>=5 && NR<=10' file
Skip header awk 'NR>1' file
Print unique values awk '!seen[$1]++' file
Print with line numbers awk '{print NR, $0}' file
Replace field 3 awk '{$3="new"; print}' file
Run inline program awk 'BEGIN{print "hello"}'
Read delimiter from var awk -v FS=, '{print $1}' file
Pass shell variable awk -v val="$VAR" '$1==val' file
Multiple input files awk '{print FILENAME, $0}' a.txt b.txt
Print field count awk '{print NF}' file
Delete duplicate lines awk '!x[$0]++' file
Print between two patterns awk '/START/,/END/' file
Negate pattern awk '!/pattern/' file
Multiple patterns awk '/foo/{x++} /bar/{y++} END{print x,y}' file
Multichar delimiter awk -F'::' '{print $2}' file
Regex delimiter awk -F'[,;]' '{print $1}' file
Write to file awk '{print > "out.txt"}' file

How awk works

An awk program is a sequence of pattern { action } rules:

awk 'pattern1 { action1 }
     pattern2 { action2 }' inputfile

For each input line:

  1. awk splits the line into fields $1, $2, … $NF using FS (default: whitespace)
  2. Each rule is tested in order; if the pattern matches, the action runs
  3. If no pattern is given, the action runs on every line
  4. If no action is given, the default action is print

Built-in variables

Variable Default Meaning
FS " " Input field separator (regex)
OFS " " Output field separator
RS "\n" Input record separator
ORS "\n" Output record separator
NR Current line number (across all files)
FNR Line number within current file
NF Number of fields in current record
$0 Entire current line
$1…$NF Individual fields
FILENAME Name of current input file
ARGC Number of command-line arguments
ARGV Array of command-line arguments
ENVIRON Array of environment variables
# Print number of fields per line
awk '{print NF}' data.txt

# Print second-to-last field
awk '{print $(NF-1)}' data.txt

# Use environment variable
awk 'BEGIN{print ENVIRON["HOME"]}'

# FNR resets per file; NR does not
awk '{print FILENAME, FNR, NR, $0}' a.txt b.txt

BEGIN and END blocks

BEGIN runs before any input is read. END runs after all input is processed.

# Print header and footer
awk 'BEGIN{print "Name\tScore"} {print $1"\t"$2} END{print "---"}' scores.txt

# Sum a column and compute average
awk '{sum+=$2; n++} END{print "avg:", sum/n}' data.txt

# Initialize variables
awk 'BEGIN{FS=","; OFS="\t"} {print $1,$3}' data.csv

Pattern types

# Regex pattern — match any line containing "error"
awk '/error/' log.txt

# Negated regex
awk '!/error/' log.txt

# Relational expression — field comparison
awk '$3 > 50' data.txt
awk '$1 == "Alice"' data.txt
awk '$2 ~ /^[0-9]+$/' data.txt   # field matches regex
awk '$2 !~ /foo/' data.txt        # field does NOT match regex

# Range pattern — from START line to END line (inclusive)
awk '/BEGIN/,/END/' file.txt

# Compound conditions
awk '$1=="error" && $3>100' log.txt
awk '/warn/ || /error/' log.txt

# Line number conditions
awk 'NR==1' file.txt           # first line only
awk 'NR>=5 && NR<=10' file.txt # lines 5–10
awk 'NR%2==0' file.txt         # even lines only

Arithmetic

awk supports full arithmetic: +, -, *, /, %, ^ (power).

# Running total
awk '{total += $2} END{print total}' sales.txt

# Compute percentage
awk '{pct = $2/$3 * 100; printf "%.1f%%\n", pct}' data.txt

# Increment counter
awk '/404/{errors++} END{print errors, "errors"}' access.log

# Built-in math functions
awk 'BEGIN{print sin(0), cos(0), sqrt(2), int(3.9), log(1), exp(1)}'
# → 0 1 1.41421 3 0 2.71828

String functions

Function Returns
length(s) Length of string (or $0 if no arg)
substr(s, start, [len]) Substring (1-indexed)
index(s, t) Position of t in s (0 = not found)
split(s, arr, [sep]) Split s into array arr, returns count
sub(r, rep, [s]) Replace first match of regex r in s
gsub(r, rep, [s]) Replace all matches of regex r in s
match(s, r) Set RSTART/RLENGTH; return start pos
sprintf(fmt, ...) Formatted string (like printf)
tolower(s) Lowercase
toupper(s) Uppercase
# Substring (1-indexed, inclusive)
echo "hello world" | awk '{print substr($0, 7)}'      # → world
echo "hello world" | awk '{print substr($0, 1, 5)}'   # → hello

# Replace first occurrence
echo "foo foo foo" | awk '{sub(/foo/, "bar"); print}'  # → bar foo foo

# Replace all occurrences
echo "foo foo foo" | awk '{gsub(/foo/, "bar"); print}' # → bar bar bar

# Replace in specific field
awk '{gsub(/,/, ";", $2); print}' data.txt

# Split field into array
awk '{n=split($1, arr, ":"); for(i=1;i<=n;i++) print arr[i]}' data.txt

# match — get position and length
echo "2026-07-14" | awk '{match($0, /[0-9]{4}/); print substr($0, RSTART, RLENGTH)}'
# → 2026

# sprintf for formatting
awk '{printf "%05d  %-20s  %8.2f\n", NR, $1, $2}' data.txt

Arrays (associative)

awk arrays are key-value maps. Keys are always strings, but numbers work via automatic coercion.

# Count occurrences
awk '{count[$1]++} END{for(k in count) print k, count[k]}' file.txt

# Group sum by key
awk -F, '{sum[$1]+=$2} END{for(k in sum) print k, sum[k]}' data.csv

# Check if key exists
awk '{if ($1 in seen) print "dup:", $1; else seen[$1]=1}' file.txt

# Delete a key
awk '{delete arr[$1]}' file.txt

# Multi-dimensional (simulated)
awk '{matrix[$1][$2]++} END{for(r in matrix) for(c in matrix[r]) print r, c, matrix[r][c]}' file.txt
# gawk syntax — mawk uses matrix[r,c] (SUBSEP-separated key)

# Sorted output (gawk only)
awk '{count[$1]++} END{PROCINFO["sorted_in"]="@val_num_desc"; for(k in count) print k, count[k]}' file.txt

printf formatting

# Syntax: printf "format", arg1, arg2, ...
awk '{printf "%-15s %5d %8.2f\n", $1, $2, $3}' data.txt

# Format specifiers
# %d   integer          %05d  zero-padded
# %f   float            %.2f  2 decimal places
# %s   string           %-10s left-aligned in 10 chars
# %e   scientific       %g    shorter of %e/%f
# %x   hex              %o    octal
# \t   tab              \n    newline

Multi-file and getline

# Process two files differently
awk 'FNR==NR{a[$1]=$2; next} $1 in a{print $1, a[$1], $2}' prices.txt items.txt
# FNR==NR is true only for the first file — classic awk two-file join

# getline — read next line explicitly
awk '/HEADER/{getline; print "after header:", $0}' file.txt

# getline from a command
awk 'BEGIN{while(("ls" | getline line) > 0) print "file:", line}'

# getline from a file
awk '{while((getline line < "lookup.txt") > 0) print line}' main.txt

Output and redirection

# Append to file
awk '{print > "output.txt"}' data.txt        # overwrite each run
awk '{print >> "output.txt"}' data.txt       # append

# Redirect to different files based on field
awk '{print > ($3 > 100 ? "high.txt" : "low.txt")}' data.txt

# Pipe to a shell command
awk '{print $2 | "sort -n"}' data.txt

# Close a pipe between iterations (to re-open fresh)
awk '{print | "sort"; close("sort")}' data.txt

# Multiple output files
awk -F, '{print > $1".txt"}' data.csv   # one file per value of $1

Practical one-liners

# Print lines between two timestamps
awk '$1 >= "10:00" && $1 <= "11:00"' access.log

# Sum file sizes from ls -l
ls -l | awk 'NR>1{sum+=$5} END{print sum, "bytes"}'

# Find lines longer than 80 chars
awk 'length > 80' file.txt

# Print only duplicate lines
awk 'seen[$0]++ == 1' file.txt

# Remove blank lines
awk 'NF' file.txt

# Extract IP addresses (first field) and count unique ones
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20

# CSV: print columns 1 and 3, skip header
awk -F, 'NR>1{print $1","$3}' data.csv

# Convert CSV to TSV
awk 'BEGIN{FS=","; OFS="\t"} {$1=$1; print}' data.csv

# Print every Nth line
awk 'NR%5==0' file.txt   # every 5th line

# Word frequency count
awk '{for(i=1;i<=NF;i++) freq[$i]++} END{for(w in freq) print freq[w], w}' text.txt | sort -rn

# Extract value from key=value log
awk '{for(i=1;i<=NF;i++) if($i~/^user=/) {split($i,a,"="); print a[2]}}' app.log

# Running average of column
awk '{sum+=$2; print $1, sum/NR}' data.txt

# Print lines where field 3 is not a number
awk '$3 !~ /^[0-9]+(\.[0-9]+)?$/' data.txt

# Transpose a matrix (rows → columns)
awk '{for(i=1;i<=NF;i++) row[i]=row[i] (NR==1?"":"\t") $i} END{for(i=1;i<=NF;i++) print row[i]}' matrix.txt

awk vs gawk vs nawk vs mawk

Feature POSIX awk gawk (GNU) mawk nawk
Arrays
\t in printf
Pipes
Multiple {print > file} open limited limited
OFMT control
getline variants partial
Regex intervals {n,m} no partial no
PROCINFO / sorted_in no no no
TCP/UDP networking no no no
Co-processes no no no
@include / @load no no no
Speed baseline slower fastest fast
macOS default nawk optional no yes (as awk)
Linux default gawk yes optional no

Use gawk when you need: regex intervals, sorted iteration, networking, or @include. Use mawk in pipelines where speed matters. On macOS, /usr/bin/awk is a BSD one-true-awk variant — install gawk via Homebrew for full features.


7 common mistakes

Mistake Problem Fix
awk '{print $1}' (quoting) Shell expands $1 before awk sees it Always use single quotes around awk programs
awk -F , '{…}' Space after -F treats , as file, not separator Use -F, (no space) or -F','
gsub(/\//, "\\") Backslash hell in replacement string Use gsub(/\//, "\\\\") — awk needs double-escape
awk 'NR==1{next} {…}' then check NR next skips to next record, doesn't reset Use FNR if checking per-file line numbers
for(k in arr) print k — wrong order Arrays iterate in arbitrary (hash) order Pipe to sort or use gawk PROCINFO["sorted_in"]
sub(/foo/, "bar&baz") & in replacement means "matched text" Escape it: "bar\\&baz"
awk '{print $0}' file > file Truncates file before awk reads it Use a temp file or sponge from moreutils

6 FAQ

Q: How do I process a CSV that has quoted fields with commas inside? awk -F, breaks on commas inside quotes. Use a proper CSV parser: Python's csv module, csvkit, or miller (mlr). For simple CSVs without quoted commas, -F, works fine.

Q: What's the difference between sub and gsub? sub replaces the first match; gsub replaces all matches. Both return the number of replacements made and modify $0 (or the third argument) in place.

Q: How do I pass a shell variable into awk? Use -v: awk -v threshold="$LIMIT" '$2 > threshold' file. Never interpolate shell variables directly inside single-quoted awk programs — it breaks the quoting. Alternatively wrap in double quotes and escape $ for awk fields: awk "\$2 > $LIMIT" — but this is fragile.

Q: How do I join two files on a common key? Classic idiom: awk 'FNR==NR{a[$1]=$2; next} $1 in a{print $1, a[$1], $2}' lookup.txt data.txt. FNR==NR is true only for the first file — it loads the lookup table. The second block matches rows in the second file.

Q: How do I handle Windows line endings (\r\n) in awk? Add sub(/\r$/, "") at the start of your action, or set RS="\r\n". On GNU awk you can also use --posix with RS="\r?\n".

Q: Is awk still worth learning in 2026? Yes. awk is on every Unix/Linux/macOS system, has no dependencies, and handles structured text (logs, CSVs, tabular data) faster than Python for quick one-liners. For complex logic or JSON, reach for Python or jq. For line-oriented text processing in shell scripts, awk is often the right tool.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools