You have a log file, a CSV export or the output of some command, and you want one column, or only the rows that match a condition, or a total. You could open a spreadsheet or write a Python script. Or you could type one line of AWK and be done. AWK reads text line by line, splits each line into fields, and lets you act on them. This guide takes you from zero to useful, with sample files you can copy and run, and the exact output you should see.
What AWK is
AWK is a small programming language built for processing text that is organised in lines and columns. The name comes from the initials of its three original authors: Aho, Weinberger and Kernighan. Most Linux systems ship with some version of it, so you can usually start right away.
The idea is simple. AWK reads your input one line (called a record) at a time. It splits each line into fields, and for every line it checks your rules. Each rule is a pattern plus an action in curly braces:
awk 'pattern { action }' file
If the pattern matches the current line, the action runs. Leave out the pattern and the action runs on every line. Leave out the action and AWK prints the matching lines.
Which awk do you have?
"awk" is a name shared by several programs. The most common are gawk (GNU awk), mawk (the default on some Debian-family systems) and the BWK awk that macOS uses. Check yours:
awk --version # works on gawk (and on the newer mawk I tested)
awk -W version # worked on both gawk 5.2.1 and mawk 1.3.4
Everything in this guide runs the same on gawk 5.2.1 and mawk 1.3.4, which are the two I tested. Where a feature works in only one of them, the article says so. I did not test macOS awk.
Create two sample files
Paste this into a terminal. Every example below uses these files.
cat > sales.csv <<'EOF'
date,region,product,qty,price
2026-10-01,north,pen,10,1.50
2026-10-01,south,book,3,12.00
2026-10-02,north,book,2,12.00
2026-10-02,east,pen,25,1.50
2026-10-03,south,pen,5,1.50
EOF
cat > access.log <<'EOF'
10.0.0.1 - - [24/Oct/2026:10:00:01 +0000] "GET /index.php HTTP/1.1" 200 512
10.0.0.2 - - [24/Oct/2026:10:00:02 +0000] "GET /about HTTP/1.1" 404 128
10.0.0.1 - - [24/Oct/2026:10:00:03 +0000] "POST /login HTTP/1.1" 302 0
10.0.0.3 - - [24/Oct/2026:10:00:04 +0000] "GET /index.php HTTP/1.1" 200 512
10.0.0.2 - - [24/Oct/2026:10:00:05 +0000] "GET /missing HTTP/1.1" 404 128
10.0.0.1 - - [24/Oct/2026:10:00:06 +0000] "GET /index.php HTTP/1.1" 500 64
EOF
Fields and records: the five things to remember
| You write | It means |
|---|---|
$0 |
The whole current line |
$1, $2, ... |
The first field, the second field, and so on |
NF |
The number of fields on the current line |
$NF |
The last field ($(NF-1) is the one before it) |
NR |
The current line number |
By default, AWK splits on runs of spaces and tabs. For a comma-separated file, tell it the separator with -F.
Print a column
awk -F, '{print $2}' sales.csv
region
north
south
north
east
south
The first line is the header. Skip it by only acting when the line number is greater than 1, and print two columns by separating them with a comma:
awk -F, 'NR>1 {print $3, $4}' sales.csv
pen 10
book 3
book 2
pen 25
pen 5
Filter rows
A pattern on its own prints every line that matches. Match a field exactly:
awk -F, '$2 == "north"' sales.csv
2026-10-01,north,pen,10,1.50
2026-10-02,north,book,2,12.00
Or match text anywhere in the line with a regular expression between slashes:
awk '/404/' access.log
10.0.0.2 - - [24/Oct/2026:10:00:02 +0000] "GET /about HTTP/1.1" 404 128
10.0.0.2 - - [24/Oct/2026:10:00:05 +0000] "GET /missing HTTP/1.1" 404 128
Combine a condition with an action. In the log, the status code is field 9 and the requested path is field 7:
awk '$9 == 404 {print $7}' access.log
/about
/missing
Do math
AWK treats numeric-looking fields as numbers, so you can add and multiply right away. Total revenue is quantity times price, added up over every row except the header:
awk -F, 'NR>1 {total += $4 * $5} END {print "Total:", total}' sales.csv
Total: 120
Two things happened there. total was never declared; AWK created it and started it at zero. And the END block ran once, after the last line, which is the right place for final results.
BEGIN and END
-
BEGIN { ... }runs once before any input is read. Use it to print a heading or set variables. It works even with no input file:awk 'BEGIN {print "Hello, AWK"}'printsHello, AWK. -
END { ... }runs once after the last line. Use it for totals. Inside it,NRholds the total number of lines, soawk 'END {print NR}' access.logprints6.
Format the output with printf
printf works like the C function: you give a format string and the values. It does not add a newline for you, so end the format with \n.
awk -F, 'NR>1 {printf "%-6s %-5s %6.2f\n", $2, $3, $4*$5}' sales.csv
north pen 15.00
south book 36.00
north book 24.00
east pen 37.50
south pen 7.50
%-6s is a left-aligned string in 6 characters, and %6.2f is a number with two decimals in 6 characters.
Count things with an array
AWK arrays are indexed by text, which makes "count by group" short to write. This counts rows per region:
awk -F, 'NR>1 {n[$2]++} END {for (k in n) print k, n[k]}' sales.csv | sort
east 1
north 2
south 2
Note the | sort at the end. It is there on purpose, and the mistakes section below explains why.
Use a variable from the shell
Pass values in with -v instead of pasting them into the program:
awk -F, -v region=north '$2 == region' sales.csv
This prints the same two north rows as before, but now the region can come from a shell variable.
Put the program in a file
When a one-liner gets long, save it and run it with -f:
# report.awk
BEGIN { FS = ","; print "Sales report" }
NR > 1 { total += $4 * $5; n++ }
END { printf "%d orders, total %.2f\n", n, total }
awk -f report.awk sales.csv
Sales report
5 orders, total 120.00
Five beginner mistakes (all tested)
1. Using double quotes around the program
The shell replaces $1 inside double quotes before AWK ever sees it. The variable is empty, so AWK receives {print } and prints whole lines:
awk "{print $1}" access.log # wrong: prints the entire line
awk '{print $1}' access.log # right: prints the first field
Wrap AWK programs in single quotes.
2. Comparing numbers when the header is in the way
You want rows with quantity over 5. This looks right:
awk -F, '$4 > 5 {print $3, $4}' sales.csv
product qty
pen 10
pen 25
The header sneaked in. In the header row, field 4 is the text qty, so AWK compares it with 5 as text, and it counts as "greater". Add NR>1 && to skip the header, and you get only pen 10 and pen 25.
3. Comma or no comma in print
A comma puts a space between the values; no comma glues them together:
echo 'a b' | awk '{print $1,$2; print $1 $2}'
# a b
# ab
4. Forgetting that new variables start empty
An unset variable is both zero and an empty string, depending on how you use it. That is why total += ... works without setup:
awk 'BEGIN {print x+0, "[" x "]"}'
# 0 []
5. Expecting array loops to come out in order
for (k in n) visits keys in no guaranteed order. When I ran the region count without sort, gawk and mawk printed the same counts in a different order. Pipe the output through sort when order matters.
AWK, grep, sed or cut?
- grep finds lines that match.
- sed edits text, mostly search and replace.
- cut slices fixed columns.
- AWK is the one to reach for when you need columns and a condition or some arithmetic.
For a quick "show me lines containing X", grep is shorter. Once you need a column, a comparison or a total, AWK pays off.
Frequently asked questions
What does AWK stand for?
The initials of its creators: Alfred Aho, Peter Weinberger and Brian Kernighan.
Is awk the same as gawk?
Not always. awk is a name that points to whichever version your system chose, and on many Linux systems it is gawk. The basics in this guide work in both gawk and mawk, but gawk adds extra features such as asort() and gensub() that mawk does not have. In my test, calling those in mawk failed with "function never defined".
Can AWK edit a file in place?
Plain AWK prints to the screen; it does not change the input file. gawk can do it with -i inplace (I tested this on gawk 5.2.1). For a method that works with any awk, write to a temporary file and then move it over the original.
Is AWK still worth learning?
For fast work on logs, CSV files and command output, yes. A few lines of AWK often replace a throwaway script. For larger programs with complex data, a general-purpose language is the better tool.
Further reading
Originally published on DEV Talk.
Top comments (0)