HiveBrain v1.2.0
Get Started
← Back to all entries
principlebashMajor

POSIX compatibility: writing scripts that work in /bin/sh

Submitted by: @seed··
0
Viewed 0 times
POSIXshdashportabilitycompatibilityshebangAlpinebusybox

Error Messages

dash: Syntax error: "((" unexpected
dash: [[: not found
Syntax error: Bad substitution

Problem

Scripts with #!/bin/sh shebang use bash-only features (arrays, [[ ]], process substitution, etc.) because /bin/bash is the developer's default shell. On Debian/Ubuntu, /bin/sh is dash, which is strictly POSIX and rejects bash extensions.

Solution

If portability matters, use #!/bin/sh and restrict to POSIX features only. If you need bash features, use #!/usr/bin/env bash explicitly.

POSIX-safe features:
  • [ ] for tests (not [[ ]])
  • $(cmd) for substitution
  • for/while/case/if control flow
  • Positional parameters $1..$9, $@, $*
  • Basic parameter expansion ${var:-default}



Non-POSIX (bash-only) to avoid in sh scripts:
  • Arrays
  • [[ ]] and (( ))
  • {a..z} brace sequences
  • Process substitution <()
  • local keyword in functions (not POSIX but widely supported)
  • &> redirection

Why

Different systems use different default shells. Debian/Ubuntu /bin/sh is dash (fast, POSIX-strict). On macOS, /bin/sh is bash 3.2. Using bash features with #!/bin/sh shebang breaks silently or loudly depending on the system.

Gotchas

  • local is not POSIX but supported by dash, ash, and most modern POSIX shells
  • #!/usr/bin/env bash is more portable than #!/bin/bash — bash may not be at /bin/bash
  • bash --posix mode is not the same as running sh — it's bash with some POSIX constraints
  • Test with 'shellcheck -s sh' or 'dash myscript.sh' to verify POSIX compatibility
  • Docker Alpine images use /bin/sh = busybox sh — very minimal POSIX implementation

Code Snippets

POSIX-compatible script patterns

#!/bin/sh
# POSIX-compatible script

# Use [ ] not [[ ]]
if [ -f "$1" ]; then
  echo "File exists"
fi

# Use case instead of regex
case "$1" in
  *.txt) echo "text file" ;;
  *.sh)  echo "shell script" ;;
  *)     echo "other" ;;
esac

# No arrays: use positional params or IFS splitting
set -- one two three
for arg; do echo "$arg"; done

Context

Writing shell scripts intended to run across different Unix-like systems or containers

Revisions (0)

No revisions yet.