All articles

Shell Scripts That Survive Beyond Bash

10 minutes read


Share this article

𝕏
Illustration for Shell Scripts That Survive Beyond Bash

Portability is less about avoiding Bash and more about making the boundary visible. A script should declare its interpreter, quote data, check commands, and fail in a way that leaves useful evidence.

Declare the interpreter

Use a shebang that matches the language you are writing:

#!/bin/sh
set -eu

If the script needs Bash arrays, [[ ... ]], or mapfile, say so with #!/usr/bin/env bash instead of accidentally depending on the caller’s shell.

Quote data and check tools

Treat paths and user input as data, even when they look harmless:

if ! command -v rsync >/dev/null 2>&1; then
  printf '%s\n' "rsync is required" >&2
  exit 127
fi

for path in "$@"; do
  printf 'checking %s\n' "$path"
done

The explicit check produces a useful error in a minimal container rather than a cryptic “not found” several lines later.

Test failure as a first-class path

Run scripts with empty input, spaces in filenames, a missing dependency, and a command that returns non-zero. A short script that behaves predictably in those cases is more portable than a clever one that only works on one workstation.

Sources and further reading
  1. POSIX — Shell Command Language
  2. ShellCheck wiki — SC2086
  3. GNU Bash manual — Bash startup files