- 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 ripgrepFedora/RHEL/CentOS Stream (dnf):
sudo dnf install -y curl jq git fzf ripgrepopenSUSE (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 fzfdnf:
sudo dnf install -y fzfzypper:
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_TOKENSlow 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 -> outputfile cache helps.Retry with backoff on 429/5xx. Respect provider rate limits.
Add
AI_MODELoverride 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, andlogsumscripts 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.