Posted on
Artificial Intelligence

Artificial Intelligence Bash Reporting

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence Bash Reporting: Turn Shell Output into Executive-Ready Summaries

Ever been buried in logs five minutes before a stand‑up? You have metrics and errors, but not a story. Artificial Intelligence (AI) can transform your raw Bash output into concise, actionable reports you can hand to your team or execs—without ripping out your existing tooling.

This article shows how to add an “AI summarizer” step to your Bash workflows. You’ll install minimal CLI tools, collect the right signals, call an OpenAI‑compatible endpoint via curl, and generate a clean Markdown report. It stays in Bash, plays nicely with cron, and works with any OpenAI‑compatible API (hosted or self‑hosted).

Why AI + Bash is a valid combo

  • You already have the data: df, ps, journalctl, dmesg, and friends. The problem is cognitive overload, not collection.

  • LLMs are great at synthesis: they turn noisy, heterogeneous text into a structured, prioritized summary with next actions.

  • Minimal surface area: use curl and jq to hit an OpenAI‑compatible endpoint. No heavy agents or long‑running daemons.

  • Portable and auditable: it’s just Bash. Easy to review, version, and schedule across fleets.


1) Install prerequisites

We’ll use curl for API calls and jq for safe JSON handling. For scheduling, use cron/cronie.

  • Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y curl jq cron
sudo systemctl enable --now cron
  • Fedora/RHEL/CentOS (dnf):
sudo dnf install -y curl jq cronie
sudo systemctl enable --now crond
  • openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y curl jq cron
sudo systemctl enable --now cron

Tip: If you don’t want scheduling yet, you can skip enabling cron for now.


2) Configure your AI endpoint and keep secrets safe

This approach works with any OpenAI‑compatible API (e.g., OpenAI, OpenRouter, Together, self‑hosted gateways). We’ll parameterize the base URL, model, and API key.

  • Create a config file:
mkdir -p ~/.config/ai-report
cat > ~/.config/ai-report/env <<'EOF'
# OpenAI-compatible base URL and model
AI_BASE_URL="https://api.openai.com/v1"
AI_MODEL="gpt-4o-mini"

# Your API key (keep private!)
AI_API_KEY="sk-REPLACE_ME"

# Optional: customize the system prompt
AI_SYSTEM_PROMPT="You are a Linux SRE assistant. You write concise, accurate Markdown reports from raw system data. Do not invent metrics. If data is missing, say so."
EOF
chmod 600 ~/.config/ai-report/env

Security notes:

  • Never commit API keys to Git.

  • Consider scoping keys to this use and applying org policies on data retention.

  • If you must process sensitive logs, filter/redact before sending to an external API—or use a self‑hosted, OpenAI‑compatible endpoint.


3) Create the Bash AI reporter

The script below:

  • Collects key signals (storage, CPU/mem, failed services, high‑priority logs, kernel tail, open ports).

  • Crafts a compact, structured prompt.

  • Calls a configurable OpenAI‑compatible API using curl.

  • Saves a Markdown report.

Save as ai-report.sh and make it executable.

#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<USAGE
AI Bash Reporting
Usage:
  $(basename "$0") [--since "24 hours ago"] [--outdir /path]

Options:
  --since   Time window for logs (journalctl -S), default: "24 hours ago"
  --outdir  Where to save the report, default: current directory
USAGE
}

SINCE="24 hours ago"
OUTDIR="$PWD"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --since)  SINCE="${2:-}"; shift 2 ;;
    --outdir) OUTDIR="${2:-}"; shift 2 ;;
    -h|--help) usage; exit 0 ;;
    *) echo "Unknown option: $1" >&2; usage; exit 1 ;;
  esac
done

# Load config if present
CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/ai-report/env"
if [[ -f "$CONFIG" ]]; then
  set -a
  # shellcheck disable=SC1090
  source "$CONFIG"
  set +a
fi

: "${AI_BASE_URL:=https://api.openai.com/v1}"
: "${AI_MODEL:=gpt-4o-mini}"
: "${AI_SYSTEM_PROMPT:=You are a Linux SRE assistant. You write concise, accurate Markdown reports from raw system data. Do not invent metrics. If data is missing, say so.}"

if [[ -z "${AI_API_KEY:-}" ]]; then
  echo "ERROR: AI_API_KEY is not set. Put it in $CONFIG" >&2
  exit 1
fi

HOST="$(hostname -f 2>/dev/null || hostname)"
NOW="$(date -Is)"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT

# Collect signals (best-effort; continue if something fails)
df -hT --exclude-type=tmpfs --exclude-type=devtmpfs > "$TMP/disk.txt" || true
ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head -n 15 > "$TMP/topcpu.txt" || true
ps -eo pid,comm,%cpu,%mem --sort=-%mem | head -n 15 > "$TMP/topmem.txt" || true
systemctl --failed > "$TMP/failed.txt" 2>/dev/null || echo "(systemctl not available or no failures)" > "$TMP/failed.txt"
journalctl -p 3 -S "$SINCE" -n 200 --no-pager > "$TMP/journal.txt" 2>/dev/null || echo "(journalctl not available or no entries)" > "$TMP/journal.txt"
dmesg --ctime | tail -n 200 > "$TMP/dmesg.txt" 2>/dev/null || echo "(dmesg not accessible)" > "$TMP/dmesg.txt"
ss -tulpen | head -n 50 > "$TMP/ports.txt" 2>/dev/null || echo "(ss not available)" > "$TMP/ports.txt"

# Optional redaction example (uncomment if needed)
# for f in "$TMP"/*.txt; do
#   sed -E -i \
#     -e 's/[0-9]{1,3}(\.[0-9]{1,3}){3}/[REDACTED_IP]/g' \
#     -e 's/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/[REDACTED_EMAIL]/g' \
#     "$f"
# done

USER_CONTENT=$(cat <<EOF
Generate a concise, actionable Markdown report for host "$HOST".
Time generated: $NOW
Time window: $SINCE

Requirements:

- Start with a TL;DR (1–3 bullets).

- Then 5–10 bullets each with: Severity (Low/Med/High), Finding, Rationale, Suggested Action.

- Cover sections: Storage, CPU/Mem, Services, Errors, Networking.

- Call out anomalies and likely root causes. Do not fabricate data.

- Keep <= 300 words. If a section is empty, state that.

### Storage (df)
\`\`\`
$(cat "$TMP/disk.txt")
\`\`\`

### Top by CPU
\`\`\`
$(cat "$TMP/topcpu.txt")
\`\`\`

### Top by Memory
\`\`\`
$(cat "$TMP/topmem.txt")
\`\`\`

### Failed Services
\`\`\`
$(cat "$TMP/failed.txt")
\`\`\`

### Recent High-Priority Logs (journalctl -p 3)
\`\`\`
$(cat "$TMP/journal.txt")
\`\`\`

### Kernel Messages (dmesg tail)
\`\`\`
$(cat "$TMP/dmesg.txt")
\`\`\`

### Listening Sockets
\`\`\`
$(cat "$TMP/ports.txt")
\`\`\`
EOF
)

PAYLOAD=$(jq -n \
  --arg model "$AI_MODEL" \
  --arg sys   "$AI_SYSTEM_PROMPT" \
  --arg content "$USER_CONTENT" \
  '{model:$model, temperature:0.2,
    messages:[
      {role:"system", content:$sys},
      {role:"user",   content:$content}
    ]}')

RESPONSE=$(curl -sS -X POST "$AI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer ${AI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d "$PAYLOAD")

REPORT=$(echo "$RESPONSE" | jq -r '.choices[0].message.content // empty')

if [[ -z "$REPORT" ]]; then
  echo "ERROR: No content returned by the model." >&2
  echo "$RESPONSE" >&2
  exit 2
fi

mkdir -p "$OUTDIR"
OUTFILE="$OUTDIR/ai-report-${HOST}-$(date +%Y%m%dT%H%M%S).md"
printf "%s\n" "$REPORT" > "$OUTFILE"
echo "Report saved to: $OUTFILE"
chmod +x ai-report.sh

Run it interactively:

./ai-report.sh --since "24 hours ago" --outdir ./reports

You’ll get a Markdown file like:

reports/ai-report-myhost-20260111T083012.md

Open it in any Markdown viewer or paste it into a ticket.


4) Schedule it (cron or systemd timers)

  • Cron example (runs every weekday at 07:00):
crontab -e

Add:

0 7 * * 1-5 /home/youruser/ai-report.sh --since "24 hours ago" --outdir /home/youruser/reports >> /home/youruser/ai-bash-report.log 2>&1

Make sure your ~/.config/ai-report/env is readable by the cron user (usually your own account) and has mode 600.

  • Systemd timer (optional, if you prefer systemd): Create ~/.config/systemd/user/ai-report.service:
[Unit]
Description=AI Bash Report

[Service]
Type=oneshot
EnvironmentFile=%h/.config/ai-report/env
ExecStart=%h/ai-report.sh --since "24 hours ago" --outdir %h/reports

Create ~/.config/systemd/user/ai-report.timer:

[Unit]
Description=Run AI Bash Report at 07:00 daily

[Timer]
OnCalendar=*-*-* 07:00:00
Persistent=true

[Install]
WantedBy=timers.target

Enable it:

systemctl --user daemon-reload
systemctl --user enable --now ai-report.timer

5) Real‑world variations and one‑liners

  • Summarize a noisy app log into action items:
tail -n 500 /var/log/nginx/error.log \
| jq -Rs --arg m "${AI_MODEL:-gpt-4o-mini}" '
  {model:$m, messages:[
    {role:"system", "content":"Summarize recurring errors, top URIs, suspected causes, and fixes. Be concise."},
    {role:"user", "content": .}
  ]}' \
| curl -sS -H "Authorization: Bearer $AI_API_KEY" -H "Content-Type: application/json" \
  -d @- "$AI_BASE_URL/chat/completions" \
| jq -r '.choices[0].message.content'
  • Post‑incident digest (last week):
./ai-report.sh --since "last week" --outdir ~/reports
  • Multi‑host (via SSH fan‑out): Use a jump host or Parallel SSH to copy and run the script across machines, then centralize the generated Markdown in a shared folder.

Tips:

  • Keep prompts short and structured. LLMs respond well to explicit format requirements.

  • Cap input sizes (e.g., last 200 lines of logs) to control cost/runtime.

  • Redact sensitive data before sending to external endpoints, or run an OpenAI‑compatible API locally.


Conclusion and next steps

You don’t need to replace your Bash tooling to get executive‑ready insights. Add a single AI summarization step and turn raw system data into a clear narrative with priorities and next actions.

Your next steps:

  • Install curl and jq via your package manager and run the sample script.

  • Tune the prompt to your team’s format (SRE weekly, on‑call handoffs, PCI/SOX friendly versions).

  • Schedule it and start archiving Markdown reports for trend analysis.

  • Consider redaction or a self‑hosted, OpenAI‑compatible endpoint if you handle sensitive logs.

Have a favorite section to add (e.g., Kubernetes events, Nginx access patterns, DB slow queries)? Drop it into the collector and let the AI do the rest.