Posted on
Artificial Intelligence

Writing Better Bash Scripts with Artificial Intelligence

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

Writing Better Bash Scripts with Artificial Intelligence

If you’ve ever shipped a Bash script that worked flawlessly on your machine but fell apart in cron or a container, you’re not alone. Bash is powerful—but unforgiving. The good news: modern AI can be a force multiplier for shell authors, helping you scaffold scripts faster, catch subtle bugs, enforce style, and even generate tests. In this post, you’ll learn practical ways to pair AI with proven CLI tools to write safer, cleaner Bash.

Why use AI for Bash?

  • Speed and scaffolding: LLMs generate boilerplate (usage blocks, argument parsing, traps) instantly, so you focus on the logic.

  • Review and refactoring: AI spots quoting issues, unnecessary subshells, and unsafe patterns that lead to production breakage.

  • Teaching and documentation: It turns arcane Bash into readable comments and usage text.

  • Test generation: It suggests Bats tests and edge cases you might miss.

AI won’t replace your judgment (or shellcheck), but it’s a great copilot—especially when you combine it with established tools like shellcheck, shfmt, and bats.


1) Install an AI‑Assisted Bash Toolkit

We’ll use:

  • shellcheck: static analysis for shell scripts

  • shfmt: consistent formatting

  • jq: JSON parsing (useful in scripts and examples)

  • bats: a TAP-compliant Bash test framework

  • shell-gpt (sgpt): a simple CLI to talk to LLMs

Set up by your distro:

Debian/Ubuntu (apt)

sudo apt update
sudo apt install -y jq shellcheck shfmt bats python3-pip
python3 -m pip install --user shell-gpt
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Fedora/RHEL/CentOS (dnf)

# On RHEL-like systems you may need EPEL for ShellCheck:
sudo dnf install -y epel-release
sudo dnf install -y jq ShellCheck shfmt bats python3-pip
pip3 install --user shell-gpt
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

openSUSE Leap/Tumbleweed (zypper)

sudo zypper refresh
sudo zypper install -y jq ShellCheck shfmt bats python3-pip
pip3 install --user shell-gpt
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Configure your AI key for sgpt (if using a hosted provider):

export OPENAI_API_KEY="your_api_key_here"
# Optional: persist across sessions
echo 'export OPENAI_API_KEY="your_api_key_here"' >> ~/.bashrc

Notes:

  • Always review and sanitize what you send to AI (strip secrets, tokens, private paths).

  • If you prefer local/offline models, you can use other CLI frontends—adapt the prompts below accordingly.


2) Scaffold a Safe, Modern Bash Script with AI

Kickstart new scripts with a consistent skeleton so you stop copy-pasting risky snippets.

Ask AI for a strict-mode template with getopts, traps, and helpful usage text:

sgpt -s "Write a Bash script skeleton that:

- uses: set -Eeuo pipefail; IFS=$'\n\t'

- implements getopts for flags: -f <file>, -v (verbose), -h (help)

- has a mktemp-based workspace and a trap that cleans it

- prints a clear usage() and exits with codes

- uses functions and safe quoting

- includes TODOs where business logic should go"

Redirect output straight into a file:

sgpt "Generate the script described above" > mytool.sh
chmod +x mytool.sh

Want a quick usage block for an existing script? Paste your script and ask for a usage synopsis and examples:

sgpt -f mytool.sh "Read this script and produce an updated usage() function and 3 realistic examples."

Pro tip:

  • Request “POSIX sh only” if you need portability, or “Bash-only features welcome” if you’re fine targeting Bash.

3) Review and Refactor with AI + ShellCheck

Static analysis remains non-negotiable. Combine it with AI for fast, targeted fixes.

Run ShellCheck on your script:

shellcheck mytool.sh

If it flags issues, ask AI to propose minimal diffs that resolve them. Feed both the script and the ShellCheck output:

sgpt -s "
You are a Bash expert. Given this script and shellcheck output,
produce a unified diff that:

- fixes quoting, arrays, and word-splitting issues

- keeps behavior the same

- uses getopts if needed

- explains key changes in comments
" -f mytool.sh -f <(shellcheck -f gcc mytool.sh)

Review the patch and apply it:

# Save AI output to a patch file
sgpt -f mytool.sh -f <(shellcheck -f gcc mytool.sh) "Create a unified diff to fix the issues." > fix.patch
git apply --check fix.patch && git apply fix.patch

Ask AI to explain a risky fragment in plain English:

sgpt -s "Explain what this Bash line does and suggest a safer rewrite:
for f in $FILES; do rm -rf $f; done"

4) Format and Enforce Style with shfmt (and Git Hooks)

Consistent formatting prevents bikeshedding and uncovers accidental changes.

Format in-place (2-space indents):

shfmt -i 2 -w .

Fail builds on style drift:

shfmt -d .

Add a simple Git pre-commit hook to block bad changes:

cat > .git/hooks/pre-commit <<'HOOK'
#!/usr/bin/env bash
set -euo pipefail
if ! command -v shfmt >/dev/null; then
  echo "shfmt not found; install it first." >&2
  exit 1
fi
if ! command -v shellcheck >/dev/null; then
  echo "shellcheck not found; install it first." >&2
  exit 1
fi

# Show formatting diffs
shfmt -d .

# Lint staged shell files
files=$(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.sh$' || true)
[ -z "$files" ] || shellcheck $files
HOOK
chmod +x .git/hooks/pre-commit

Tip: You can also ask AI to “write a stricter hook that skips vendor/ and supports *.bash” and then review its output.


5) Generate Tests with Bats (and Let AI Propose Cases)

Even small scripts deserve tests, especially for flags and error paths.

Create a minimal Bats test:

mkdir -p test
cat > test/mytool.bats <<'BATS'
#!/usr/bin/env bats

setup() {
  TMPDIR="$(mktemp -d)"
}

teardown() {
  rm -rf "$TMPDIR"
}

@test "shows help with -h" {
  run ./mytool.sh -h
  [ "$status" -eq 0 ]
  [[ "$output" == *"Usage:"* ]]
}

@test "fails when missing -f <file>" {
  run ./mytool.sh
  [ "$status" -ne 0 ]
  [[ "$output" == *"Usage:"* ]]
}
BATS
chmod +x test/mytool.bats
bats test/

Ask AI to propose more tests (edge cases, invalid inputs, perms):

sgpt -f mytool.sh -s "Generate 5 Bats tests that cover:

- verbose mode

- failure when file doesn't exist

- non-writable temp dir

- handling spaces in filenames

- exit codes"

Then copy useful cases into test/ and iterate.


Real-World Example: Hardening a Cleanup Script

Original snippet:

#!/usr/bin/env bash
for f in $FILES; do
  rm -rf $f
done

What AI suggests (and why):

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

# Expect FILES as an array to avoid word-splitting bugs
# Usage: FILES=("dir 1" "dir 2") ./cleanup.sh
FILES=("${FILES[@]:-}")

for f in "${FILES[@]}"; do
  # Defensive: refuse to remove root or empty var expansions
  [[ -n "$f" && "$f" != "/" ]] || { echo "Refusing to remove '$f'"; exit 1; }
  rm -rf -- "$f"
done
  • Quotes prevent splitting on spaces.

  • -- stops rm from parsing a filename that starts with a dash.

  • Guards prevent catastrophic deletions.

You can prompt the AI: “rewrite safely for arrays, strict mode, and dangerous-path guards.”


Safety, Privacy, and Good Habits

  • Never paste secrets into prompts. Redact tokens and keys:
sed -E 's/(AWS|GITHUB|API|SECRET|TOKEN)_[A-Z0-9_]+=.*/\1_REDACTED=***REDACTED***/g' script.sh > script.public.sh
  • Pair AI with shellcheck and tests; don’t skip verification.

  • Prefer patches/diffs over entire rewrites—smaller, auditable changes.

  • Explicitly request portability (POSIX) or Bash features depending on your target.


Conclusion and Next Steps

AI won’t turn weak scripts into great ones by itself—but with the right workflow, it accelerates everything you already know is good practice: strict mode, safe quoting, consistent style, and tests.

Your next 30 minutes: 1) Install the toolkit (shellcheck, shfmt, bats, sgpt). 2) Run shellcheck on one existing script. 3) Ask AI for a minimal diff to fix issues; apply and review. 4) Add a Bats test file with at least two cases. 5) Add the pre-commit hook and run shfmt -w ..

Once that’s done, consider wiring these tools into CI and using AI to draft a one-page README. Share the before/after with your team—you’ll set a new bar for Bash quality.