Shell Scripting AWK Reports Advanced May 2026

Shell Scripting Advanced AWK: Complete Report Generator

Build a full production AWK report — multi-section output with headers, totals, grouped summaries, bar charts, and a complete infrastructure daily report script combining all AWK techniques from this section.

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.

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)
}'
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)
}
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}"
awk — daily_report.awk output
════════════════════════════════════════════════════════════
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.