Posted on
Artificial Intelligence

Artificial Intelligence Bash Debugging with Local LLMs

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

Artificial Intelligence Bash Debugging with Local LLMs

Ever lost a full afternoon to a 15‑line Bash script? You add set -x, sift through 500 lines of trace, and still can’t see the root cause. What if you could hand the log and the script to a tireless, local “pair debugger” that summarizes the failure, explains the ShellCheck output, and proposes a minimal, safe fix—all without sending your code to the cloud?

This post shows how to use a local LLM (Large Language Model) as a Bash debugging copilot. You’ll get concrete installation instructions, practical workflows, and drop‑in scripts to make your next Bash bug a non‑event.

Why use a local LLM for Bash debugging?

  • Privacy and compliance: Everything stays on your machine—perfect for regulated environments or proprietary scripts.

  • Speed: No network latency, no rate limits. You can iterate fast.

  • Contextual reasoning: LLMs are excellent at summarizing noisy traces, explaining ShellCheck output in plain English, and proposing diffs.

  • Works with your tools: Combine with shellcheck, bash -x, and logs for a powerful debugging loop.

What we’ll build

  • Install a local LLM runtime (Ollama or llama.cpp).

  • Pair it with ShellCheck and Bash tracing.

  • Add a command to explain errors and generate minimal patches (unified diffs).

  • Use prompts that produce safe, auditable changes.


1) Install the essentials

We’ll use:

  • A local LLM runtime:

    • Easy mode: Ollama (downloads and runs models for you).
    • Advanced: llama.cpp (build from source; you control everything).
  • Debugging helpers: ShellCheck, jq, ripgrep (optional but handy).

Install ShellCheck and CLI helpers

  • Debian/Ubuntu (apt):

    sudo apt update
    sudo apt install -y shellcheck jq ripgrep curl git
    
  • Fedora/RHEL/CentOS (dnf):

    sudo dnf install -y ShellCheck jq ripgrep curl git
    
  • openSUSE (zypper):

    sudo zypper refresh
    sudo zypper install -y ShellCheck jq ripgrep curl git
    

Option A: Install Ollama (simple, batteries included)

Ollama provides a single command installer and manages models locally.

curl -fsSL https://ollama.com/install.sh | sh
# Then start the service if not already running:
sudo systemctl enable --now ollama

Pull a model suited for code reasoning (choose one you have resources for):

# Popular general model:
ollama pull llama3.1

# Or a code-focused model (if available in your Ollama catalog):
ollama pull codellama:7b-instruct

Test it:

ollama run llama3.1 "Summarize: set -euo pipefail in Bash"

Option B: Install llama.cpp (full control, build from source)

1) Install build dependencies:

  • Debian/Ubuntu (apt):

    sudo apt update
    sudo apt install -y build-essential cmake git curl
    
  • Fedora/RHEL/CentOS (dnf):

    sudo dnf groupinstall -y "Development Tools"
    sudo dnf install -y cmake git curl
    
  • openSUSE (zypper):

    sudo zypper refresh
    sudo zypper install -y gcc-c++ make cmake git curl
    

2) Build llama.cpp:

git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j

3) Download a GGUF model (code models recommended; choose a size your machine can handle). For example, fetch a small instruct model from a reputable source, then run:

# Example run (adjust path/model filename to what you downloaded)
./build/bin/llama-cli -m ./models/your-model.gguf -p "Explain set -euo pipefail"

Tip: For CPU‑only systems, select 4‑bit or 5‑bit quantized (Q4_K_M, Q5_K_M) models for decent speed.


2) A baseline debugging example

Here’s a flawed script that looks simple, but breaks in real setups (spaces in filenames, empty globs, brittle ls):

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

SRC=${1:-/mnt/source}
DST=${2:-/mnt/backup}

echo "Copying *.txt from $SRC to $DST..."
for f in $(ls $SRC/*.txt); do
  cp $f $DST
done

echo "Done."

Common issues:

  • Iterating over ls output is fragile.

  • Unquoted variables cause word splitting and globbing problems.

  • Globs may expand unexpectedly or fail when nothing matches.

Run ShellCheck to surface issues:

shellcheck ./backup.sh

You’ll typically see warnings like:

  • Don’t use ls in for-loops; iterate globs directly.

  • Double-quote variables to prevent word splitting.


3) Workflow: ShellCheck + LLM explanation and patch

Use a local LLM to translate ShellCheck output into an actionable, minimal diff.

Save this helper as explain-shellcheck.sh:

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

file="${1:?Usage: $0 path/to/script.sh}"

report="$(shellcheck "$file" || true)"
script="$(sed -n '1,300p' "$file")"

read -r -d '' PROMPT << 'EOF'
You are a senior Bash engineer. Given a ShellCheck report and the script:
1) Explain the findings in plain English.
2) Propose a minimal, safe fix as a unified diff (patch) from the current file.
3) Keep portability in mind (POSIX where possible).
Only output: Explanation, then a unified diff.
EOF

# With Ollama (change model as you prefer)
ollama run llama3.1 <<EOF
${PROMPT}

--- SHELLCHECK REPORT ---
${report}

--- SCRIPT (${file}) ---
${script}
EOF

Make it executable:

chmod +x explain-shellcheck.sh

Run it:

./explain-shellcheck.sh ./backup.sh

You should get a human‑readable explanation followed by a unified diff you can review and apply with git apply or patch.


4) Workflow: Trace, summarize, and fix with a single command

When a script fails, capture the bash -x trace and ask the LLM to localize the bug and propose a patch. Add this shell function to your ~/.bashrc or ~/.bash_functions:

aidebug() {
  local file="${1:?usage: aidebug path/to/script.sh}"
  local args="${*:2}"

  # Capture a clean set -x trace
  local trace
  trace="$(
    ( set -o pipefail; bash -x "$file" $args </dev/null ) \
      1>/tmp/aidebug.out 2>&1 || true
  )"

  local script
  script="$(sed -n '1,400p' "$file")"

  cat >/tmp/aidebug.prompt <<'PROMPT'
You are a meticulous Bash debugger.

- Read the script and the bash -x trace.

- Identify the root cause in 1–3 bullet points.

- Propose a minimal, safe fix as a unified diff.

- Explain any quoting/globbing changes and their impact on edge cases (spaces, empty globs).
PROMPT

  ollama run llama3.1 <<EOF
$(cat /tmp/aidebug.prompt)

--- TRACE (bash -x) ---
${trace}

--- SCRIPT (${file}) ---
${script}
EOF
}

Usage:

aidebug ./backup.sh "/path/with spaces" ./dest

Review the root cause summary and the generated diff. Apply only after reading—and consider adding tests.


5) Real‑world hardening: from brittle to robust

A robust rewrite the LLM might suggest (for illustration):

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

SRC=${1:?Usage: backup.sh SOURCE DEST}
DST=${2:?Usage: backup.sh SOURCE DEST}

# Ensure target exists
mkdir -p -- "$DST"

# Enable nullglob so empty matches don't produce literal patterns
shopt -s nullglob

# Iterate files safely; quote expansions; use -- to end options
for f in "$SRC"/*.txt; do
  cp -- "$f" "$DST"/
done

echo "Copied *.txt from '$SRC' to '$DST'."

Key improvements:

  • Quotes around variables prevent word splitting.

  • shopt -s nullglob handles “no matches” gracefully.

  • -- disambiguates file names from options.

  • Clear usage messages via parameter expansion.


Prompting tips for consistent, safe results

  • Ask for “minimal, safe diff” to avoid sprawling rewrites.

  • Provide both the script and the exact bash -x trace.

  • Call out concerns: quoting, globbing, portability, non‑GNU systems.

  • Keep contexts short (<= 300–500 lines) for snappier responses.


Optional: Run the same workflows with llama.cpp

If you prefer llama.cpp, replace the ollama run ... line with an invocation of llama-cli and a prompt file, for example:

./build/bin/llama-cli \
  -m ./models/your-model.gguf \
  -p "$(cat /tmp/aidebug.prompt)
--- TRACE (bash -x) ---
${trace}

--- SCRIPT (${file}) ---
${script}"

You may want to experiment with -c (context size) and -n (tokens) for longer inputs.


Frequently used installs (summary)

  • Debian/Ubuntu:

    sudo apt update
    sudo apt install -y shellcheck jq ripgrep curl git \
                      build-essential cmake
    
  • Fedora/RHEL/CentOS:

    sudo dnf install -y ShellCheck jq ripgrep curl git \
                      cmake gcc-c++ make
    # Optionally:
    sudo dnf groupinstall -y "Development Tools"
    
  • openSUSE:

    sudo zypper refresh
    sudo zypper install -y ShellCheck jq ripgrep curl git \
                          gcc-c++ make cmake
    

Conclusion and next steps

Local LLMs turn opaque Bash failures into clear, actionable fixes—without compromising privacy or speed. You now have:

  • A local LLM runtime (Ollama or llama.cpp).

  • A workflow that pairs ShellCheck with AI explanations and minimal diffs.

  • A one‑liner aidebug function to summarize traces and propose patches.

Call to action:

  • Install Ollama, pull a model, and run ./explain-shellcheck.sh on one of your existing scripts today.

  • Drop aidebug into your shell and try it on your next flaky cron job.

  • Wrap these helpers in a git pre‑commit hook to catch issues before they land.

If this sped up your debugging day, share your prompt tweaks and diffs with your team—and add these tools to your standard Linux dev toolbox.