This page brings together everything from the Advanced AWK section into a single, complete production report generator. It demonstrates how functions, arrays, formatting, and multi-file joins all work together in a real AWK program — something you would actually commit, schedule in cron, and email to management every morning.
1
AWK functions — defining and reusing logic
AWK
# Functions must appear before they are called
# or in any pattern block (AWK is single-pass)
awk '
function hr(n, i, s) {
s = ""
for (i=0; i=1024 && s<5; s++) b /= 1024
return sprintf("%.1f%s", b, u[s])
}
function human_time(s, d, h, m) {
d=int(s/86400); h=int((s%86400)/3600); m=int((s%3600)/60)
if (d>0) return sprintf("%dd%dh%dm", d, h, m)
if (h>0) return sprintf("%dh%dm%ds", h, m, s%60)
return sprintf("%dm%ds", m, s%60)
}
BEGIN {
print "Function library loaded"
print hr(40)
print pct_bar(75, 100, 20), "75%"
print human_bytes(1536000)
print human_time(90065)
}'
2
Multi-section formatted report
AWK
#!/usr/bin/awk -f
# daily_report.awk — Daily infrastructure report
function sep(char, n, i, s) {
s=""
for (i=0; i<n; i++) s=s char
return s
}
function bar(v, m, w, f, b, i) {
f=int(v/m*w); b=""
for (i=0; i<f; i++) b=b "#"
for (i=f; i<w; i++) b=b "."
return b
}
BEGIN {
FS = ","
DATE_CMD = "date '+%Y-%m-%d %H:%M'"
DATE_CMD | getline report_date
close(DATE_CMD)
print sep("═", 60)
printf " INFRASTRUCTURE DAILY REPORT — %s\n", report_date
print sep("═", 60)
}
# First file: metrics.csv (hostname,cpu,mem,disk,status)
FNR==NR {
if (FNR==1) next
host=$1; cpu=$2; mem=$3; disk=$4; status=$5
total_hosts++
if (status=="UP") up++; else down++
cpu_sum += cpu; mem_sum += mem; disk_sum += disk
if (cpu > max_cpu) { max_cpu=cpu; max_cpu_host=host }
if (disk > 85) disk_alerts[host]=disk
if (status!="UP") down_hosts[host]=status
next
}
# Second file: errors.csv (hostname,error_count,error_type)
FNR>1 {
errors[$1] += $2
err_type[$1] = $3
}
END {
# ── Section 1: Fleet Overview ─────────────────────────────
print "\n FLEET OVERVIEW"
print " " sep("─", 40)
printf " %-20s %d\n", "Total servers:", total_hosts
printf " %-20s %d (%d%%)\n", "Servers UP:", up, up/total_hosts*100
printf " %-20s %d\n", "Servers DOWN:", down
printf " %-20s %.1f%%\n", "Avg CPU:", cpu_sum/total_hosts
printf " %-20s %.1f%%\n", "Avg Memory:", mem_sum/total_hosts
printf " %-20s %s (%.0f%%)\n", "Max CPU:", max_cpu_host, max_cpu
# ── Section 2: Disk Alerts ────────────────────────────────
if (length(disk_alerts) > 0) {
print "\n ⚠ DISK ALERTS (>85%)"
print " " sep("─", 40)
for (h in disk_alerts)
printf " %-20s %s %s\n", h, bar(disk_alerts[h],100,20),
disk_alerts[h]"%"
}
# ── Section 3: Down Servers ───────────────────────────────
if (length(down_hosts) > 0) {
print "\n ✘ DOWN SERVERS"
print " " sep("─", 40)
for (h in down_hosts)
printf " %-20s %s\n", h, down_hosts[h]
}
# ── Section 4: Error Summary ──────────────────────────────
if (length(errors) > 0) {
print "\n ERROR COUNTS"
print " " sep("─", 40)
for (h in errors)
printf " %-20s %5d %s\n", h, errors[h], err_type[h]
}
print "\n" sep("═", 60)
}
3
Running the complete report
BASH
#!/usr/bin/env bash
# run_report.sh — Generate and send the daily AWK report
set -euo pipefail
REPORT_DIR="/opt/myapp/reports"
REPORT_FILE="${REPORT_DIR}/daily_$(date +%Y%m%d).txt"
# Collect metrics from all servers
echo "hostname,cpu,mem,disk,status" > /tmp/metrics.csv
for srv in web-01 web-02 db-01 cache-01; do
ssh -o BatchMode=yes "${srv}" \
"echo \$(hostname),\$(top -bn1|awk '/Cpu/{gsub(/%us,/,\"\");print \$2}'),\$(free|awk '/Mem/{printf \"%.0f\",\$3/\$2*100}'),\$(df /|awk 'NR==2{gsub(/%/,\"\");print \$5}'),UP" \
>> /tmp/metrics.csv 2>/dev/null \
|| echo "${srv},0,0,0,DOWN" >> /tmp/metrics.csv
done
# Collect error counts
echo "hostname,error_count,error_type" > /tmp/errors.csv
for srv in web-01 web-02 db-01; do
ssh -o BatchMode=yes "${srv}" \
"cnt=\$(grep -c ERROR /var/log/myapp/app.log 2>/dev/null||echo 0); echo \$(hostname),\$cnt,APP_ERROR" \
>> /tmp/errors.csv 2>/dev/null
done
# Generate report
awk -f /opt/myapp/scripts/daily_report.awk \
/tmp/metrics.csv /tmp/errors.csv > "${REPORT_FILE}"
# Send by email
cat "${REPORT_FILE}" | mail -s "[Daily] Infrastructure Report $(date +%Y-%m-%d)" \
ops@example.com management@example.com
echo "Report sent: ${REPORT_FILE}"
════════════════════════════════════════════════════════════
INFRASTRUCTURE DAILY REPORT — 2026-05-01 06:00
════════════════════════════════════════════════════════════
FLEET OVERVIEW
────────────────────────────────────────
Total servers: 4
Servers UP: 3 (75%)
Servers DOWN: 1
Avg CPU: 47.5%
Max CPU: prod-db-01 (91%)
⚠ DISK ALERTS (>85%)
prod-db-01 #################### 91%
█
✔ Complete AWK programs — Store complex AWK in
.awk files and run with awk -f report.awk. Define all functions at the top. Use the two-file join pattern (FNR==NR) to combine data sources. Use BEGIN to run shell commands via getline for runtime data like dates. Structure reports with separator lines, section headers, and conditional sections that only appear when data exists.