The awk command is a pattern-scanning and text-processing language designed for structured text.
It is especially useful for log analysis, CSV-like data extraction, reporting, and one-line transformations.
Overview
Use awk when you need to:
- Split lines into fields and operate on specific columns
- Filter records using conditions and regular expressions
- Aggregate data (sum, counts, min/max)
- Reformat text output into reports
- Perform lightweight ETL-style transformations in shell pipelines
Syntax
awk [options] 'program' [file...]
Common invocation forms:
# Inline program
awk 'pattern { action }' input.txt
# Set field separator
awk -F',' '{ print $1, $3 }' data.csv
# Load program from file
awk -f script.awk input.txt
# Pass variables from shell
awk -v limit=100 '$2 > limit { print $0 }' metrics.txt
awk evaluates each input record (usually one line at a time), applies matching patterns,
and executes actions for records that match.
Program Structure
An awk program is made of pattern-action pairs:
pattern { action }
Special blocks:
BEGIN { ... }: Runs once before reading inputEND { ... }: Runs once after all input is processed- Omitted pattern: Action runs for every record
- Omitted action: Matching records are printed by default
Example:
awk 'BEGIN { print "Start" } /ERROR/ { print NR, $0 } END { print "Done" }' app.log
Fields and Records
By default:
- Record separator
RSis newline - Field separator
FSis whitespace
Useful field and record references:
| Token | Meaning |
|---|---|
$0 |
Entire current record (line) |
$1 ... $N |
Individual fields |
NF |
Number of fields in current record |
NR |
Current overall record number |
FNR |
Current record number in current file |
Field separator examples:
# Comma-separated fields
awk -F',' '{ print $1, $2 }' users.csv
# Colon-separated fields (e.g., /etc/passwd)
awk -F: '{ print $1, $7 }' /etc/passwd
Common Options
| Option | Purpose | Example |
|---|---|---|
-F |
Set input field separator | -F',' |
-v |
Define variable before execution | -v threshold=90 |
-f |
Read awk program from file | -f report.awk |
-- |
End options (GNU awk) | awk -- '...' file |
Operators and Conditions
Common comparison operators:
==,!=,<,<=,>,>=
Common logical operators:
&&(AND),||(OR),!(NOT)
Regex matching operators:
~matches regex!~does not match regex
Examples:
# Numeric filter
awk '$3 >= 100 { print $1, $3 }' sales.txt
# Regex filter
awk '$0 ~ /ERROR|WARN/ { print NR, $0 }' app.log
# Combined logic
awk '$2 == "active" && $5 > 10 { print $1 }' accounts.txt
Built-In Variables
| Variable | Meaning |
|---|---|
FS |
Input field separator |
OFS |
Output field separator |
RS |
Input record separator |
ORS |
Output record separator |
NF |
Number of fields in current record |
NR |
Total records read so far |
FNR |
Records read in current file |
FILENAME |
Current input filename |
Formatting output with OFS:
awk -F',' 'BEGIN { OFS=" | " } { print $1, $3, $5 }' data.csv
Useful Built-In Functions
| Function | Purpose | Example |
|---|---|---|
length(s) |
Length of string | length($1) |
substr(s, i, n) |
Substring | substr($1, 1, 3) |
index(s, t) |
Position of substring | index($0, "ERROR") |
tolower(s) / toupper(s) |
Case conversion | tolower($1) |
split(s, a, sep) |
Split string into array | split($1, parts, ":") |
gsub(r, x, s) |
Replace all matches | gsub(/foo/, "bar", $0) |
sub(r, x, s) |
Replace first match | sub(/^[ ]+/, "", $0) |
sprintf(fmt, ...) |
Build formatted string | sprintf("%.2f", $3) |
Examples
# Print first and third columns from CSV
awk -F',' '{ print $1, $3 }' data.csv
# Print line numbers for matching log entries
awk '/ERROR/ { print NR ": " $0 }' app.log
# Sum values in column 2
awk '{ sum += $2 } END { print sum }' metrics.txt
# Count occurrences by key (column 1)
awk '{ count[$1]++ } END { for (k in count) print k, count[k] }' events.txt
# Print username and shell from /etc/passwd
awk -F: '{ print $1, $7 }' /etc/passwd
# Skip header row in CSV and print selected fields
awk -F',' 'NR > 1 { print $1, $4 }' users.csv
# Replace text inline in output stream (without modifying source file)
awk '{ gsub(/staging/, "production"); print }' config.txt
Safe Usage Guidelines
- Quote awk programs with single quotes in Bash to prevent shell expansion.
- Validate delimiters (
-F) before assuming column positions. - Test transformations on sample data before applying to production pipelines.
- Use explicit numeric conversions when needed to avoid string/number confusion.
- Prefer readable multi-line awk scripts (
-f) for complex logic.
Performance Tips
- Filter early with patterns to avoid unnecessary action blocks.
- Avoid expensive regex operations when simple field comparisons are sufficient.
- Use one
awkpass for multiple calculations instead of chaining many tools. - For very large inputs, reduce string allocations and unnecessary concatenation.
Troubleshooting
Fields are not splitting correctly
Cause: Incorrect field separator.
Fix: Verify delimiter and set -F explicitly.
awk -F',' '{ print NF, $0 }' data.csv
Variables from shell are empty inside awk
Cause: Shell variable not passed with -v.
Fix: Pass values explicitly:
awk -v needle="$Needle" '$0 ~ needle { print }' app.log
Output order from associative arrays looks random
Cause: Iteration order for for (k in arr) is not guaranteed.
Fix: Pipe output to sort when deterministic ordering is required.
awk '{ count[$1]++ } END { for (k in count) print k, count[k] }' events.txt | sort
Notes
Most Linux distributions provide GNU Awk (gawk) by default.
Run man awk and man gawk for implementation-specific details.