SwiftRelay

← All sprint notes

Before the Green Light: A Shell Script Trust Checklist

First lapsEN

Write a Script That Fails Loudly

A shell script is a short list of commands that the shell runs from top to bottom. The shell is very forgiving when you type at a prompt: if one command fails, you notice immediately and type something else. Inside a script the shell shows the same patience, so the file keeps running after a mistake and hands you output that only looks complete. Trust starts with refusing that behaviour.

Begin with the shebang, the first line that tells the system which interpreter to run the file with. #!/usr/bin/env bash is a safe choice because it finds bash wherever it is installed. Right below it, turn on the three settings that move the shell from forgiving to strict.

  • set -e stops the script the moment a command fails instead of carrying on to the next line.
  • set -u treats a missing variable as an error, which catches typos in variable names early.
  • set -o pipefail makes a whole pipeline fail when any command inside it fails, so a clean-looking final step cannot hide a broken first step.

With those few lines in place, a failure ends the run immediately. You find the problem while it is still small, instead of discovering it later in a pile of half-finished files. That is the first lap of a trustworthy script.

Quote Variables and Guard Your Inputs

Quoting is the next habit worth building. When a variable holds a name such as holiday photos.jpg, writing $file without quotes spreads it into two separate words, and the command receives arguments it never expected. Put double quotes around every expansion: rm "$file", cp "$source" "$target", and test -f "$config". The quotes cost nothing and remove a whole class of surprise.

Guarding your inputs is the other half of the same idea. Check what the script was given before it uses anything.

  • Count the arguments and print a short usage message when the number is wrong.
  • Test that files and directories exist before you read, copy or move them.
  • Reject empty strings early, because an empty variable usually means a missing environment variable or a mistyped flag.
  • Give destructive steps explicit confirmation, and end option parsing with -- so a file called -r is never read as a switch.

Written this way, the script either receives a clean job to do or tells you exactly what is missing. A message like usage: backup.sh SOURCE DEST at the top of the run saves a confusing five minutes later on.

Turn Failures Into Clear Signals

Every command returns a status, and zero means success. Reading those statuses is how a script explains itself to a human. Print your own messages to standard error so they do not mix into the data the script produces, and include the line number so you know where to look: printf "failed at line %s\n" "$LINENO" >&2.

trap lets you run a small piece of code when the script exits or when a command fails. trap 'printf "stopped at line %s\n" "$LINENO"' ERR turns a silent stop into a readable one, and a trap ... EXIT handler is the right place to delete temporary files or release a lock. That way the script leaves the machine tidy even when it is interrupted.

Be careful with deletion. Never write rm -rf $dir unquoted, because an empty variable turns it into a very different command. A calmer pattern is to move results into a dated folder and delete only after you have checked them. Deleting is the one place where a pause is cheaper than an apology.

Run the Small Lap Before the Big Job

Trust is easier to build when you can watch a run before the run counts. Add a dry-run mode to scripts that change anything. A variable such as DRY_RUN can switch between printing a command and running it: when it is set, the script prints would run: ... and stops there. You get to read the plan as text and catch a wrong path before it is used.

A short testing pass works well for any script.

  • Run shellcheck over the file and fix what it reports, since it spots missing quotes and unused variables that look harmless.
  • Run the script with bash -x once to see each command as the shell expands it.
  • Point it at sample data inside a scratch directory, never at the real files first.
  • Run it twice and confirm the second run does the same thing, which shows the script is repeatable.
  • Check the exit code afterwards with echo $? so a failure is never swallowed by a later successful command.

That small lap takes a few minutes and turns a script you hope works into a script you have seen work.

Keep Keys and Model Calls Outside the Script

Secrets and network calls belong outside the script body. Store an API key in an environment variable or in a file with restricted permissions, and read it at runtime with something like key=$(cat ~/.config/mytool/key). Keep key files out of version control with a .gitignore entry, and never paste a key into a command you might later share as an example. If a script prints debug output, print the variable name and not its value.

The same care applies to calling a language model from a script. SwiftRelay is a pay-as-you-go relay for Claude, GPT, Gemini, DeepSeek, Kimi, GLM, Qwen, Grok and other models, and it works with Claude Code, Codex, Gemini CLI and any OpenAI-compatible SDK. The API host is https://api.fastapirelay.com, where Claude Code and Gemini CLI take the bare host and OpenAI-compatible SDKs add /v1. Billing is per token, which suits scripts that run occasionally rather than constantly, and a pipeline can spend a little on a cheap pass such as Claude Haiku 4.5 before handing the harder step to GPT-5.6 Sol.

Keep the request itself in a small function, pass the key through an environment variable, and check the response status before you use the body. A failure should print which model and which step failed, so you can retry just that part. If you want a place to start, sign up for SwiftRelay, where new accounts get a small gift credit and inviting friends earns 14% of their top-ups.

The Pit-Stop Checklist Before the Green Light

Before you let a script touch real work, run through a short list. It is the same list whether the script copies logs or writes a model summary to a report.

  • The shebang is present, and set -euo pipefail is near the top.
  • Every variable is quoted, and every input is checked before use.
  • Failures print a message with a line number, and cleanup runs on exit.
  • A dry run has shown you the commands that would execute.
  • Keys come from the environment, and nothing secret appears in output or in version control.
  • The script has been run twice against sample data, and the exit code was checked.

A trustworthy shell script is not a clever one. It is a script that stops early, speaks clearly, and refuses to guess. Build those habits once and every future script you write starts from the same solid ground.

Keep reading

Back for another lap?Log in