Posted on
Artificial Intelligence

Creating Interactive Bash Tools with Artificial Intelligence

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

Creating Interactive Bash Tools with Artificial Intelligence

Ever wish your terminal could read between the lines—explain cryptic errors, write great commit messages, or summarize logs? With a few small scripts and an AI API, your everyday Bash tools can feel conversational, context-aware, and fast.

This post shows you how to wire AI into your Bash workflow responsibly and efficiently, with practical examples you can copy today.

Why AI + Bash is worth your time

  • Bash is the glue of Linux. Most real-world workflows already pass text between small tools. AI excels at interpreting and transforming text—perfect synergy.

  • You keep your command-line speed. No new GUI, no heavyweight IDE plugins. Your scripts remain simple, composable, and shell-native.

  • You control the boundaries. Decide what to send to AI, redact sensitive data, cap costs with small models and token limits, and add caching if needed.

Caveats to keep in mind:

  • Privacy: Anything you send to a hosted model leaves your machine. Scrub secrets and consider self-hosted models if required.

  • Latency and cost: Keep prompts tight, prefer “mini” models for routine tasks, and enforce token limits.

  • Failure handling: APIs can throttle or fail—script defensively.

Prerequisites

You’ll need curl and jq to call and parse AI API responses. Some examples also use git, fzf, and ripgrep (optional).

Install with your package manager:

  • Debian/Ubuntu (apt):

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

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

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

You’ll also need an API key from your preferred provider. The examples below show OpenAI via HTTPS. You can adapt the wrapper to other vendors (Anthropic, Google, self-hosted with Ollama, etc.).

Safe environment setup for your API key

Avoid putting keys directly into your shell history. Create a small env file and source it:

mkdir -p ~/.config/ai
chmod 700 ~/.config/ai
printf 'OPENAI_API_KEY=REPLACE_WITH_YOUR_KEY\n' > ~/.config/ai/env
chmod 600 ~/.config/ai/env

# Source automatically in new shells
if ! grep -q 'source ~/.config/ai/env' ~/.bashrc 2>/dev/null; then
  printf '\n# AI API key\nset -a\n[ -f ~/.config/ai/env ] && source ~/.config/ai/env\nset +a\n' >> ~/.bashrc
fi

# Apply to current shell
set -a
source ~/.config/ai/env
set +a

Tip: Consider a secrets manager (pass, gnome-keyring, 1Password CLI) for production use.

A tiny provider-agnostic AI wrapper for Bash

Start with a single script that takes stdin as the prompt and prints the model’s reply. Save as ~/bin/ai and make it executable.

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

: "${OPENAI_API_KEY:?Set OPENAI_API_KEY (see setup section)}"

MODEL="${AI_MODEL:-gpt-4o-mini}"
MAX_TOKENS="${AI_MAX_TOKENS:-300}"
TEMPERATURE="${AI_TEMPERATURE:-0.2}"
SYSTEM_PROMPT="${AI_SYSTEM_PROMPT:-You are a concise Linux terminal assistant. Output plain text suitable for Bash.}"

prompt="$(cat)"

resp="$(curl -sS https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer ${OPENAI_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d "$(jq -nc \
        --arg model "$MODEL" \
        --arg sys "$SYSTEM_PROMPT" \
        --arg content "$prompt" \
        --argjson temp "$TEMPERATURE" \
        --argjson max "$MAX_TOKENS" \
        '{model:$model,
          messages:[{role:"system", content:$sys},{role:"user", content:$content}],
          temperature:$temp,
          max_tokens:$max}')" )"

# Basic error surfacing
if echo "$resp" | jq -e '.error' >/dev/null 2>&1; then
  echo "AI API error:" >&2
  echo "$resp" | jq -r '.error | tojson' >&2 || echo "$resp" >&2
  exit 1
fi

# Print the model's text
echo "$resp" | jq -r '.choices[0].message.content'

Make it executable and add to PATH:

chmod +x ~/bin/ai
export PATH="$HOME/bin:$PATH"

Optional environment knobs:

export AI_MODEL=gpt-4o-mini
export AI_MAX_TOKENS=300
export AI_TEMPERATURE=0.2
export AI_SYSTEM_PROMPT="You are a terse Linux assistant. Prefer bullet points."

Swap provider: Replace the curl block with your vendor’s endpoint and jq parsing. Keep the same stdin/stdout contract so your tools don’t change.

1) Explain any command or error on the fly

Create a helper that gathers local context (type/man) and asks the AI for a focused, safe explanation. Save as ~/bin/explain.

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

if [ $# -eq 0 ]; then
  echo "Usage: explain <command or error text>" >&2
  exit 1
fi

query="$*"
cmd="$(printf '%s\n' "$query" | awk '{print $1}')"

{
  echo "Explain what this does and any gotchas. Prefer examples. Keep it brief."
  echo
  echo "User input:"
  echo "$query"
  echo
  echo "--- type -a $cmd ---"
  type -a -- "$cmd" 2>&1 || true
  echo
  echo "--- man (first 120 lines) ---"
  man -P cat "$cmd" 2>/dev/null | col -b | sed -n '1,120p' || echo "No local man page."
} | ai

Usage:

explain 'find . -type f -mtime -1 -print0 | xargs -0 tar -czf backup.tar.gz'
explain 'Permission denied while trying to bind to port 80'

Why this works:

  • AI sees structured local hints (type, man snippet) to ground the answer.

  • You keep sensitive data out by only sending what you choose.

2) Generate tidy Conventional Commits from staged changes

Turn diffs into clear messages. Save as ~/bin/commit-ai.

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

if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "Not a git repository." >&2
  exit 1
fi

if [ -z "$(git diff --staged --name-only)" ]; then
  echo "No staged changes. Use: git add <files>" >&2
  exit 1
fi

# Keep prompts budget-friendly: cap sizes
status="$(git status --porcelain=v1)"
diff="$(git diff --staged --unified=0 --no-color | sed -n '1,2000p')"

msg="$(
  {
    echo "Write a single-line Conventional Commit for these staged changes."
    echo "Scope if obvious, otherwise omit. No trailing period."
    echo "Then add a short body with bullets (max 4) if needed."
    echo
    echo "--- status ---"
    echo "$status"
    echo
    echo "--- diff (truncated) ---"
    echo "$diff"
  } | AI_MAX_TOKENS=${AI_MAX_TOKENS:-280} ai
)"

echo
echo "Suggested commit message:"
echo "-------------------------"
echo "$msg"
echo "-------------------------"
read -r -p "Use this message? [y/N] " ans
if [[ "$ans" =~ ^[Yy]$ ]]; then
  git commit -m "$msg"
else
  echo "Aborted."
fi

Usage:

git add -A
commit-ai

Tips:

  • Keep diffs small; AI doesn’t need every unchanged hunk.

  • For monorepos, add a hint like “This is a frontend change” to the prompt.

3) Summarize recent system logs into actionable bullets

Focus on what changed and what to do next. Save as ~/bin/logsum.

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

# Collect recent logs with a sensible fallback
logs="$(
  journalctl -p 4 -n 200 --no-pager 2>/dev/null \
  || tail -n 200 /var/log/syslog 2>/dev/null \
  || tail -n 200 /var/log/messages 2>/dev/null \
  || true
)"

if [ -z "$logs" ]; then
  echo "No logs found (need systemd or readable /var/log/*)." >&2
  exit 0
fi

# Trim to reduce token usage
logs="$(printf '%s\n' "$logs" | sed -n '1,400p')"

{
  echo "Summarize the following logs into 5-8 bullets:"
  echo "- Group repeated errors."
  echo "- Call out root causes and specific next steps."
  echo "- Note services impacted."
  echo
  echo "--- logs (truncated) ---"
  echo "$logs"
} | AI_MAX_TOKENS=${AI_MAX_TOKENS:-260} ai

Usage:

logsum

Optional: Filter first with ripgrep to focus the prompt:

journalctl -n 1000 --no-pager | rg -i 'error|failed|timeout' | sed -n '1,400p' | ai

4) Make anything interactive with fzf + AI

fzf can turn AI output into an interactive menu. Example: turn a natural-language request into command candidates, then let the user pick.

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

: "${FZF_DEFAULT_OPTS:=--height 60% --border}"

query="${*:-list large files recursively and show sizes human readable}"

candidates="$(
  {
    echo "Turn the user request into 5 safe bash one-liners."
    echo "Use standard tools (find, du, awk). Linux only."
    echo "Print only the commands, each on its own line."
    echo
    echo "User request: $query"
  } | AI_MAX_TOKENS=220 ai
)"

cmd="$(printf '%s\n' "$candidates" | fzf --prompt="Pick a command> ")"
[ -z "${cmd:-}" ] && exit 0

echo "Selected:"
echo "$cmd"
read -r -p "Run it now? [y/N] " go
[[ "$go" =~ ^[Yy]$ ]] && bash -c "$cmd"

Dependencies reminder (install with your package manager):

  • apt:

    sudo apt install -y fzf
    
  • dnf:

    sudo dnf install -y fzf
    
  • zypper:

    sudo zypper install -y fzf
    

Safety tips:

  • Always print and confirm before running AI-generated commands.

  • Consider a sandbox user, container, or dry-run flags.

Production-hardening checklist

  • Limit tokens and truncate inputs. Keep AI_MAX_TOKENS low and cap log/diff lines.

  • Redact secrets. Pipe through a scrubber (e.g., replace tokens/keys with ****).

  • Cache frequent prompts. Even a simple input_sha -> output file cache helps.

  • Retry with backoff on 429/5xx. Respect provider rate limits.

  • Add AI_MODEL override per script if precision/price tradeoffs vary.

Conclusion and next steps

You don’t need a framework to make AI genuinely useful in your terminal—just curl, jq, and a thoughtful prompt. Start with the wrapper, then bolt on explainers, commit assistants, and log summarizers tailored to your stack.

Call to action:

  • Install the prerequisites with your package manager.

  • Drop the ai, explain, commit-ai, and logsum scripts into ~/bin.

  • Customize prompts and guardrails for your environment.

  • Share your best Bash+AI ideas and improvements with your team.

Your command line just got conversational—now put it to work.