Posted on
Artificial Intelligence

Artificial Intelligence Automation Case Studies

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

Automating Real Work with AI: 3 Bash-Friendly Case Studies for Linux

If you’re a Linux user who lives in Bash, you’ve probably felt the grind: sifting through noisy logs, turning recordings into notes, or keying data from invoices. AI can cut this toil dramatically—without abandoning your command line or bolting on heavyweight platforms. In this article, you’ll see three practical case studies you can run with standard Linux tools and a few well-placed API calls.

What you get:

  • Clear value: less repetitive work, faster insight, and more consistent outputs

  • Why it works: combine Unix philosophy (small tools, well-joined) with AI

  • 3 real-world automations with scripts you can adapt

  • Installation instructions for apt, dnf, and zypper where needed

  • A short checklist to ship these safely

Note: The examples use local preprocessing (awk/sed/ffmpeg/tesseract) and, where helpful, an LLM via HTTP. You control what leaves your machine.


Why this is worth your time

  • AI thrives on pattern-heavy text. Logs, tickets, transcripts, and invoices are perfect candidates.

  • Linux already excels at transforming text and scheduling work. Bash is ideal “glue.”

  • The fastest ROI comes from summaries, classifications, and extraction—lightweight AI tasks that remove manual triage and error-prone retyping.

  • Privacy and cost control are possible: do the heavy lifting locally (filtering, OCR, chunking), then only send strictly necessary snippets to an LLM.


Common prerequisites

Install what we’ll use across the examples:

  • curl and jq for HTTP + JSON

  • Python and pip for optional CLI tools

  • ffmpeg (for audio)

  • tesseract-ocr and poppler-utils (for OCR/PDF)

  • cron or systemd timers for scheduling

Debian/Ubuntu (apt):

sudo apt update
sudo apt install -y curl jq python3 python3-pip ffmpeg tesseract-ocr poppler-utils cron

Fedora/RHEL/CentOS (dnf):

sudo dnf install -y curl jq python3 python3-pip ffmpeg tesseract poppler-utils cronie

openSUSE (zypper):

sudo zypper install -y curl jq python3 python3-pip ffmpeg tesseract poppler-tools cron

Notes:

  • On RHEL-like systems, tesseract may require EPEL.

  • If you prefer systemd timers, cron/cronie is optional.

Environment variables for LLM API usage (example: OpenAI; set once in your shell profile):

export OPENAI_API_KEY="sk-REPLACE_ME"
export OPENAI_MODEL="gpt-4o-mini"

Case Study 1: Overnight Log Triage and a 5‑Minute Brief

Problem: On-call engineers spend hours scanning logs after incidents. We want an automatic daily brief that highlights top errors, new patterns, and suggested next steps.

What this does:

  • Collects yesterday’s high-signal logs (journalctl + Nginx example)

  • Pre-aggregates locally (privacy + lower cost)

  • Sends a compact sample to an LLM for a short, actionable summary

  • Optionally posts to Slack or writes a Markdown report

Install (tools used: jq, curl, cron/systemd):

  • Already covered in prerequisites.

Script: log-brief.sh

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

: "${OPENAI_API_KEY:?Set OPENAI_API_KEY}"
MODEL="${OPENAI_MODEL:-gpt-4o-mini}"
WORKDIR="${WORKDIR:-/var/tmp/log-brief}"
mkdir -p "$WORKDIR"

YDATE="$(date -u -d 'yesterday' +%F)"
REPORT="$WORKDIR/daily-brief-$YDATE.md"

collect_logs() {
  LOGBUF="$WORKDIR/raw-$YDATE.txt"
  : > "$LOGBUF"

  # System errors from yesterday
  if command -v journalctl >/dev/null 2>&1; then
    journalctl -p err -S yesterday -U today --no-pager 2>/dev/null | tail -n 5000 >> "$LOGBUF" || true
  fi

  # Nginx errors (if present)
  if [[ -f /var/log/nginx/error.log ]]; then
    awk -v d="$(date -d 'yesterday' '+%Y/%m/%d')" '$0 ~ d {print}' /var/log/nginx/error.log | tail -n 5000 >> "$LOGBUF" || true
  fi

  # Deduplicate noisy lines
  sort "$LOGBUF" | uniq -c | sort -nr | head -n 200 > "$WORKDIR/top-errors-$YDATE.txt"

  # Build short context (keep under ~12KB)
  head -c 12000 "$WORKDIR/top-errors-$YDATE.txt" > "$WORKDIR/context-$YDATE.txt"
}

ask_llm() {
  local prompt_file="$1"
  jq -n \
    --arg model "$MODEL" \
    --arg sys "You are a pragmatic SRE assistant. Summarize recurring errors, spot new patterns, suggest 3-5 concrete next steps. Keep it concise and scannable." \
    --rawfile usr "$prompt_file" \
  '{
    model: $model,
    messages: [
      {role:"system", content:$sys},
      {role:"user", content:$usr}
    ],
    temperature: 0.2
  }' \
  | curl -sS https://api.openai.com/v1/chat/completions \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer '"$OPENAI_API_KEY"'" \
      --connect-timeout 10 --max-time 60 \
      -d @- \
  | jq -r '.choices[0].message.content // "No content"'
}

main() {
  collect_logs
  {
    echo "# Daily Log Brief – $YDATE"
    echo
    echo "Top error snippets (local aggregation):"
    echo
    sed -E 's/[A-Fa-f0-9]{8,}/<HASH>/g' "$WORKDIR/top-errors-$YDATE.txt" | head -n 50 | sed 's/^/  /'
    echo
    echo "AI Summary:"
    echo
    ask_llm "$WORKDIR/context-$YDATE.txt"
    echo
    echo "_Generated: $(date -u +"%F %T UTC")_"
  } > "$REPORT"

  echo "Wrote $REPORT"
}

main "$@"

Schedule with cron (Debian/Ubuntu):

crontab -e
# Add:
15 6 * * * /usr/local/bin/log-brief.sh >> /var/log/log-brief.log 2>&1

Or as a systemd timer (recommended for reliability):

# /etc/systemd/system/log-brief.service
[Unit]
Description=Daily log brief

[Service]
Type=oneshot
ExecStart=/usr/local/bin/log-brief.sh

# /etc/systemd/system/log-brief.timer
[Unit]
Description=Run daily log brief at 06:15

[Timer]
OnCalendar=*-*-* 06:15:00
Persistent=true

[Install]
WantedBy=timers.target

# Enable
sudo systemctl daemon-reload
sudo systemctl enable --now log-brief.timer

Optional: Post to Slack via incoming webhook.

curl -X POST -H 'Content-type: application/json' \
  --data "$(jq -Rs --arg pretext "Daily Log Brief $YDATE" '{text: $pretext + "\n```" + . + "```"}' < "$REPORT")" \
  https://hooks.slack.com/services/TOKEN/REPLACE/ME

Case Study 2: Turn Recordings into Searchable Notes

Problem: Meeting and support call recordings are underused because they’re locked in audio. We’ll transcribe locally using Whisper, then generate a crisp summary.

Install Whisper (requires Python/pip and ffmpeg):

  • Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y ffmpeg python3 python3-pip
pip3 install -U openai-whisper torch --index-url https://download.pytorch.org/whl/cpu
  • Fedora/RHEL/CentOS (dnf):
sudo dnf install -y ffmpeg python3 python3-pip
pip3 install -U openai-whisper torch --index-url https://download.pytorch.org/whl/cpu
  • openSUSE (zypper):
sudo zypper install -y ffmpeg python3 python3-pip
pip3 install -U openai-whisper torch --index-url https://download.pytorch.org/whl/cpu

Transcribe a folder of audio files:

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

MODEL_SIZE="${WHISPER_MODEL:-base}"   # tiny, base, small, medium, large
LANG="${LANGUAGE:-en}"

for f in "$@"; do
  echo "Transcribing: $f"
  whisper "$f" --model "$MODEL_SIZE" --language "$LANG" --task transcribe --output_format txt
done

echo "Done. Generated .txt files next to audio."

Optional: Summarize transcripts with an LLM:

#!/usr/bin/env bash
set -euo pipefail
: "${OPENAI_API_KEY:?Set OPENAI_API_KEY}"
MODEL="${OPENAI_MODEL:-gpt-4o-mini}"

for t in *.txt; do
  SUMMARY="$(jq -n \
      --arg model "$MODEL" \
      --arg sys "You create action-oriented meeting notes with bullet points, decisions, owners, and deadlines. Be concise." \
      --rawfile usr "$t" \
      '{model:$model,messages:[{role:"system",content:$sys},{role:"user",content:$usr}],temperature:0.2}' \
    | curl -sS https://api.openai.com/v1/chat/completions \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer '"$OPENAI_API_KEY"'" \
        --connect-timeout 10 --max-time 60 \
        -d @- \
    | jq -r '.choices[0].message.content')"
  echo "$SUMMARY" > "${t%.txt}.summary.md"
  echo "Wrote ${t%.txt}.summary.md"
done

Tips:

  • For long recordings, run Whisper with the “small” model first (faster) and only re-run with “medium/large” if needed.

  • Redact PII locally before summarizing to control exposure.


Case Study 3: OCR Invoices to Validated JSON

Problem: Accounting teams spend hours retyping vendor name, invoice number, date, and totals. We’ll use Tesseract for OCR, then ask an LLM to extract a clean JSON payload for your ERP.

Install (OCR and PDF tools):

  • Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y tesseract-ocr poppler-utils jq
  • Fedora/RHEL/CentOS (dnf):
sudo dnf install -y tesseract poppler-utils jq
  • openSUSE (zypper):
sudo zypper install -y tesseract poppler-tools jq

Script: ocr-invoice.sh

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

: "${OPENAI_API_KEY:?Set OPENAI_API_KEY}"
MODEL="${OPENAI_MODEL:-gpt-4o-mini}"

in="$1"
work="${WORKDIR:-/tmp/invoice-ocr-$$}"
mkdir -p "$work"

to_text() {
  local src="$1"
  if [[ "$src" =~ \.pdf$ ]]; then
    pdftoppm -png -r 300 "$src" "$work/page"
    for img in "$work"/page-*.png; do
      tesseract "$img" "$img" -l eng --psm 6 >/dev/null 2>&1
    done
    cat "$work"/page-*.png.txt
  else
    tesseract "$src" "$work/scan" -l eng --psm 6 >/dev/null 2>&1
    cat "$work/scan.txt"
  fi
}

TEXT="$(to_text "$in" | sed -E 's/([0-9]{4})[0-9]{6,}([0-9]{2,4})/\1…REDACTED…\2/g' | head -c 16000)"

PAYLOAD="$(jq -n \
  --arg model "$MODEL" \
  --arg sys "You extract invoice fields from OCR text and return strict JSON. If unknown, use null." \
  --argjson schema '{
      vendor_name:"string",
      invoice_no:"string",
      invoice_date:"YYYY-MM-DD",
      total_amount:"number",
      currency:"ISO-4217"
    }' \
  --arg txt "$TEXT" \
'{
  model: $model,
  messages: [
    {role:"system", content:$sys},
    {role:"user", content:
      ("Extract this JSON with keys: " + ($schema|tostring) +
       ". Return only JSON, no prose.\n\nOCR:\n" + $txt)
    }
  ],
  temperature: 0
}' \
| curl -sS https://api.openai.com/v1/chat/completions \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer '"$OPENAI_API_KEY"'" \
    --connect-timeout 10 --max-time 60 \
    -d @- \
| jq -r '.choices[0].message.content' )"

# Validate and normalize JSON
echo "$PAYLOAD" | jq '{
  vendor_name: .vendor_name // null,
  invoice_no: .invoice_no // null,
  invoice_date: .invoice_date // null,
  total_amount: (try (.total_amount|tonumber) catch null),
  currency: .currency // null,
  source: "'"$in"'"
}'

Usage:

./ocr-invoice.sh ./samples/invoice-001.pdf > invoice-001.json

Tips:

  • Add vendor-specific rules (e.g., sed to normalize “Total” variants) before calling the LLM.

  • For large PDFs, sample key pages (first/last, pages near “Total”) to reduce cost.


Actionable Practices That Make AI Automation Work

1) Minimize and pre-structure data locally

  • Filter, dedup, and truncate with awk/sed/sort before any API call.

  • Redact PII or hashes locally. Only send what the model truly needs.

2) Treat prompts as specs

  • Write short, explicit instructions and enforce output formats (e.g., “return only JSON”).

  • Validate responses with jq and fail closed on parse errors.

3) Put guardrails on cost and reliability

  • Limit input bytes; chunk long texts.

  • Use curl timeouts and retries; log failures to a dead-letter queue (a folder).

  • Cache results for deterministic inputs (hash the input and skip rework).

4) Ship like any other ops task

  • Run via systemd timers, capture logs to journald, and export metrics (counts, durations, costs).

  • Keep secrets in environment files with locked-down permissions.

5) Start small, measure outcomes

  • Track time saved and error rates before/after.

  • Expand only after a stable win on a narrow workflow.


Conclusion and Next Steps

You don’t need a new platform to get AI value. With a few CLI tools and careful prompts, you can:

  • Triage logs while you sleep

  • Turn recordings into notes in minutes

  • Convert invoices into validated JSON

Pick one case study, run it on a small batch, and iterate. As your confidence grows, wire it into your daily jobs and notify your team via Slack or email.

If you want to go further:

  • Add unit tests around your Bash functions and jq validators

  • Introduce per-project API budgets

  • Explore local or self-hosted models later, after the workflow proves itself

Your terminal is already an AI ops console—now it just needs a few scripts.