awk Cheatsheet - Linux Text Processing Reference
Logs and reports share one trait — one field per line — and awk's strength is working on columns: counting status codes in an access log, summing values per user, joining files on a key. One awk program replaces a Python script here. The sheet runs from basic syntax through built-in variables, conditionals, statistics, string functions and common scenarios, forming the complete skeleton: a pattern plus an action per line, with BEGIN and END blocks. Built-in variables come first because everything depends on them: FS splits input, OFS separates output, NR is the global record number and NF the field count. The statistics group rests on associative arrays: count[$9]++ tallies by field value and sum[group]+=value accumulates by group, and with an END block they produce a finished report. The division of labour: sed rewrites lines without understanding columns, awk understands columns and can aggregate, and cut extracts but computes nothing.
Typical Use Case
For engineers building reports and analysing logs. Keep the division of labour with sed straight: sed edits or deletes lines, awk extracts columns and computes. This sheet is organised into six groups — basic syntax, built-in variables, conditionals, statistics, string functions and common patterns. The three patterns worth memorising are column extraction piped through sort/uniq for counting, conditional extraction such as $9 == 500 {print $7}, and BEGIN/END blocks, which are awk's distinguishing feature for pre- and post-processing.
Basic Syntax 6
awk '{print $1}' fileawk -F: '{print $1, $3}' /etc/passwdawk '{print $1, $NF}' fileawk '{print NR, $0}' fileawk 'NR==10' fileawk 'NR>=10 && NR<=20' fileBuilt-in Variables 8
$0$1, $2, $NFNRNFFSOFSRSORSConditionals 6
awk '$3 > 100' fileawk '$1 == \"error\"' fileawk '$1 ~ /pattern/' fileawk '$1 !~ /pattern/' fileawk 'NR==1 || $1 > 100' fileawk '$1 == \"a\" {print $2}' fileStatistics 5
awk '{sum += $1} END {print sum}' fileawk '{sum += $1} END {print sum/NR}' fileawk '{count++} END {print count}' fileawk '{count[$1]++} END {for(k in count) print k, count[k]}' fileawk 'BEGIN{max=0} {if($1>max) max=$1} END{print max}' fileString Functions 7
length($0)substr($0, 5, 10)index($0, \"text\")split($0, arr, \":\")sub(/old/, \"new\", $0)gsub(/old/, \"new\", $0)tolower($0) / toupper($0)Common Patterns 5
awk '{print $1}' access.log | sort | uniq -c | sort -rnawk '$9 == 500 {print $7}' access.logawk -F, '{print $2, $3}' data.csvawk 'BEGIN{OFS=\",\"} {print $1, $2}' fileawk '{sum+=$5} END{print sum/1024/1024 \" MB\"}' fileParameter matrix
| Parameter | Effect | Example |
|---|---|---|
{print $1} | Print the 1st column (whitespace-separated by default) | awk '{print $1}' file |
-F<sep> | Specify the input delimiter | awk -F: '{print $1, $3}' /etc/passwd |
$0 | The whole line | awk '{print NR, $0}' file |
$NF | The last column (most useful when the column count varies) | awk '{print $1, $NF}' file |
NR / NF | Current line number / number of fields in the current line | awk 'NR==10' file |
FS / OFS | Input / output delimiters | awk 'BEGIN{OFS=","} {print $1, $2}' file |
$3 > 100 | Numeric comparison (awk auto-detects numbers) | awk '$3 > 100' file |
$1 ~ /pat/ | Regex match (!~ for no match) | awk '$1 ~ /^error/' app.log |
BEGIN / END | Run once before / after processing | awk '{sum+=$1} END {print sum}' file |
sum += $1 | Accumulate, can be combined with END output | awk '{sum+=$1} END {print sum/NR}' file |
count[$1]++ | Group and count with an associative array | awk '{c[$1]++} END {for(k in c) print k, c[k]}' file |
sub / gsub | Replace the first / all matches | gsub(/old/, "new", $0) |
split / substr | Split into an array by delimiter / extract a substring | split($0, arr, ":") |
Pipeline composition | Combine with sort / uniq for counting | awk '{print $1}' f | sort | uniq -c | sort -rn |
Common pitfalls
SymptomThe columns awk extracts are all empty, or the whole line is treated as one field.
CauseThe delimiter does not match: the file is colon-separated but -F: was not given, and awk splits on whitespace by default.
FixUse head to look at the real delimiter first, then specify the correct one with awk -F: or -F,.
SymptomThe sum comes out as 0 or abnormally large.
CauseThe column contains non-numeric characters (such as units or timestamps) that are treated as 0 in the computation.
FixUse head to confirm the data format; if needed gsub away the non-numeric characters first, or force numeric conversion with $1+0.
SymptomThe END block cannot access the accumulator variable.
CauseThe scope of the accumulator variable differs between the main block and the END block (commonly because the variable is declared inside a conditional branch).
FixInitialize the accumulator in the BEGIN block, or make sure the first assignment of the accumulation statement is at the top level rather than inside a branch.
SymptomA regex in awk matches nothing.
CauseSpecial characters in the regex (. * + ? [ ]) must be escaped.
FixFor literal matching use /\./ or index/substr instead of a regex; do not put string quotes around the two sides of ~.
SymptomCounting occurrences of each item, every count comes out as 1.
CauseThe pipeline is missing sort; the awk associative array does not sort itself, but not aggregating first causes duplicate entries to be overwritten.
FixWrite all four steps: awk extraction | sort | uniq -c | sort -rn.
SymptomOutput columns run together with no separation.
Causeprint separates multiple expressions with OFS by default, but OFS was not set explicitly and the comma-separated form was treated as string concatenation.
FixSet the output delimiter with BEGIN{OFS=","}; separate expressions with commas in print $1, $2.
SymptomWhen handling fields that contain spaces, the whole line gets split apart.
CauseThe default FS is whitespace (including space and Tab), so a field whose value contains a space gets broken up.
FixSet FS to a fixed single character: -F" " or -F"|".
Troubleshooting
1First confirm the data delimiter and column positions
head -3 fileSee the real delimiter before writing expressions; this avoids most rework from being unable to get the column.
2Count the top 20 access counts
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20Extract column, sort and aggregate, count, then sort numerically descending; all four steps are required.
3Extract fields by condition
awk '$9 == 500 {print $7}' access.log$9 is the status code and $7 is the URL; put the condition first and the action in {}.
4Compute a column sum and convert units
awk '{sum+=$5} END {print sum/1024/1024 " MB"}' fileOutput the result in the END block; concatenating the unit as a string is the clearest.
5Group and count by the first column
awk '{c[$1]++} END {for(k in c) print k, c[k]}' fileawk arrays are associative, so any value can be used as a key directly.
Command Examples
Group and count by the first column
awk '{count[$1]++} END {for(k in count) print k, count[k]}' access.log | sort -k2 -rn | headcount[$1]++ uses the array subscript as the key and accumulates line by line; the END block outputs everything after all input is read. Append sort to order by count, since awk itself does not sort.
Output
203.0.113.7 1842 198.51.100.22 931 192.0.2.180 407
Sum a column and convert to MB
awk '{sum += $5} END {printf "%.2f MB\n", sum/1024/1024}' access.logUse printf in END to control output precision and the unit. Write the division step by step; awk does not support a power operator like 1024*1024.
Output
482.31 MB
Emit CSV by setting OFS
awk -F, 'BEGIN{OFS=","} NR>1 {print $2, $3}' data.csv > out.csv-F, sets the input delimiter to a comma and OFS sets the output delimiter. NR>1 skips the CSV header row, otherwise the title gets written into the result too.
Common Pitfalls
- Field references start at 1 and $0 is the whole line; there is no $1[0].
- awk splits on whitespace by default; parsing CSV or colon-separated files requires an explicit -F or every line becomes one field.
- Set OFS once in BEGIN — putting it in the main rule resets it on every record.
- Commas inside quoted CSV fields are treated as separators; FPAT handles the harder cases.
- awk does not sort. Pipe through sort | uniq or the result is unordered.
Tips
- awk splits on whitespace or tabs by default; use -F to specify another separator.
- The BEGIN block runs before processing, the END block runs after.
- awk arrays are associative (hash tables); keys can be strings.
FAQ
Do awk field references start at 0 or 1?
They start at 1. $0 is the whole record, $1 the first field, $2 the second, and $NF the last. This trips people up because arrays also use arr[1]. In awk $1 always means a column, not an array element, and $NF is especially handy when the number of columns varies between records.
How do I compute grouped counts in awk?
Use a count array plus an END block: awk '{count[$1]++} END {for(k in count) print k, count[k]}' file counts occurrences grouped by the first column. Counting IP hits in a log becomes awk '{print $1}' access.log | sort | uniq -c | sort -rn. For a sum use awk '{sum += $1} END {print sum}', and divide by NR for an average.
What is the difference between NF and $NF?
NF is the number of fields in the current record — a number. $NF is the value of the last field — a string. Both appear together when columns vary: test NF < 3 to skip malformed lines, or use $(NF-1) for the second-to-last field. Confusing the two produces a type error at runtime.
How do I test whether a field matches a regex in awk?
Use the ~ operator: awk '$1 ~ /pattern/' file to match and awk '$1 !~ /pattern/' file to invert. index($1, "pattern") is the equivalent for plain substring search, but it takes a literal string and cannot handle regexes. To test the whole record, just write /pattern/.
How do I make awk emit CSV?
Set the output field separator: awk 'BEGIN{OFS=","} {print $1, $2}' file prints comma-separated values. Set it once in BEGIN, not inside the main rule, or it will be reset on every record. For a quoted CSV variant, add a quote variable and build the field manually inside print.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us