Overview
Introduction
A script written and tested against Bash often breaks the moment it runs inside an Alpine container, where /bin/sh is BusyBox's ash, not Bash, and Bash-only syntax like arrays or [[ ]] either errors out or silently behaves differently.
This tool generates a script skeleton that deliberately avoids every common bashism, so the result runs identically on dash, BusyBox ash, and Bash's own sh-compatibility mode.
What Is POSIX Shell Script Generator?
A POSIX /bin/sh script skeleton generator: shebang, set -eu, a trap on EXIT/INT/TERM (not the Bash-only ERR pseudo-signal) wired to a cleanup routine, a timestamped log() function, and a getopts argument-parsing loop, all built without arrays, [[ ]], or the local keyword.
Like the Bash Script Generator, you define custom single-letter flags with a description and variable name, but every generated construct here is checked against strict POSIX shell syntax rather than Bash's extended syntax.
How POSIX Shell Script Generator Works
Instead of Bash's `set -euo pipefail`, the script uses `set -eu`, since `pipefail` isn't part of POSIX; instead of a `local exit_code=$?` inside cleanup(), the script assigns to a plain (function-scoped-by-convention, not shell-enforced) global variable, since `local` is a widely supported but non-POSIX extension.
The trap only listens for EXIT, INT, and TERM, real signals plus the shell's own exit event, since POSIX trap has no equivalent to Bash's ERR pseudo-signal; correctness instead relies on `set -e` to stop the script the moment any command fails.
When To Use POSIX Shell Script Generator
Use it for any script that needs to run inside a minimal container image (Alpine, distroless, BusyBox-based) where Bash may not be installed at all.
It's also useful for Docker ENTRYPOINT or init scripts, which conventionally target /bin/sh precisely because it's guaranteed present even on the smallest base images.
Often used alongside Bash Script Generator, systemd Service Generator and Crontab Generator.
Features
Advantages
- Produces a script that runs unmodified across dash, BusyBox ash, and Bash's sh mode, avoiding a whole class of 'works on my machine, breaks in the container' bugs.
- Explicitly avoids the specific bashisms (arrays, [[ ]], local, ERR trap) most likely to silently misbehave rather than error out clearly under a different shell.
- Still gets you a real getopts argument-parsing loop, logging, and cleanup trapping, POSIX doesn't mean primitive.
Limitations
- No array support means anything genuinely needing an ordered, indexable collection needs a different data structure (a newline-delimited string, or multiple positional variables) instead.
- No ERR trap means the script can't automatically log the exact failing line the way the Bash generator's skeleton does; you rely on set -e stopping execution and your own log() calls around risky commands.
- getopts alone (POSIX) only supports single-character flags, exactly like the Bash version, no --long-option parsing without a hand-rolled loop.
Examples
Best Practices & Notes
Best Practices
- Test the generated script with dash explicitly (many distros ship it as /bin/sh already) even if you develop on a machine where /bin/sh happens to be Bash.
- Use case statements for all conditionals in the logic you add, rather than reaching for [[ ]], which will fail outright under dash/ash.
- Avoid relying on echo's flag behavior (like -e) since it differs across shells; prefer printf, exactly as the generated log() function does.
Developer Notes
The generator produces syntax that is valid under POSIX.1-2018's shell command language grammar specifically: no array assignment syntax, no local keyword, no [[ ]] compound command, and a trap that only names EXIT, INT, and TERM (real signals recognized by trap universally, unlike Bash's ERR pseudo-signal which POSIX doesn't define). The getopts optstring and case-based dispatch are otherwise structurally identical to the Bash Script Generator's output, since getopts itself is already a POSIX-specified builtin.
POSIX Shell Script Generator Use Cases
- Writing a Docker ENTRYPOINT or init script for an Alpine or other minimal base image
- Building a shell script intended to run across a variety of Linux distributions with different default /bin/sh implementations
- Learning or auditing which specific constructs count as bashisms versus portable POSIX shell
Common Mistakes
- Copying Bash idioms like arrays or [[ ]] into a script that's supposed to run under /bin/sh, which then fails specifically inside minimal containers where /bin/sh isn't Bash.
- Assuming set -eu covers pipeline failures the way set -euo pipefail does in Bash; POSIX has no pipefail, so a failing early stage in a pipe can still be masked by a later stage's success.
- Using local inside a function for a variable that should genuinely be scoped, since POSIX sh has no local, an accidental global reused elsewhere in the script needs an explicit unique name instead.
Tips
- If you need Bash-only conveniences (arrays, [[ ]], associative arrays) and the target definitely has Bash installed, use the Bash Script Generator instead; this tool is specifically for when you can't assume that.
- Run `shellcheck --shell=sh <script>` (or `checkbashisms` in Debian's devscripts package) after filling in your logic to catch any bashism you may have introduced by hand.