← Back to Bash Course | Chapter 14: Best Practices & Real-World Scripting | Lesson 6 of 7

Writing Portable Scripts (Bash-isms vs POSIX sh)

Some Bash features only work in Bash itself, so a script that needs to run on more minimal shells has to avoid those and stick to a smaller, more universal set of commands.

Choosing the Right Shebang

#!/usr/bin/env bash looks up bash on the current PATH rather than assuming it lives at /bin/bash, which makes a script more portable across systems (like some BSDs or containers) where bash is installed elsewhere.

Example: Choosing the Right Shebang

bash
#!/usr/bin/env bash
echo "found bash via PATH lookup, running fine"

Bash-Only Features to Watch For

Arrays, [[ ]] conditionals, local variables inside functions, and string substitution like ${var//pattern/repl} are all bash extensions that a strict POSIX sh does not support.

Warning: None of the features in this example (arrays, [[ ]], ${var//a/b}) are guaranteed to work under #!/bin/sh on every system.

Example: Bash-Only Features to Watch For

bash
#!/bin/bash
fruits=("apple" "banana")
if [[ ${#fruits[@]} -eq 2 ]]; then
    echo "arrays and [[ ]] are bash-specific features working here"
fi

text="hello-world"
echo "${text//-/ }"

Writing the POSIX-Compatible Equivalent

When portability to plain sh matters, the same logic can usually be expressed with single-bracket [ ] tests, case statements, and plain variables instead of arrays, all of which are part of the POSIX standard.

Example: Writing the POSIX-Compatible Equivalent

bash
#!/bin/bash
value="banana"
case $value in
    apple) echo "it's an apple" ;;
    banana) echo "it's a banana (POSIX-compatible case statement)" ;;
    *) echo "unknown fruit" ;;
esac

if [ "$value" = "banana" ]; then
    echo "single-bracket test also works everywhere"
fi
Common Mistakes
  1. Using #!/bin/sh as the shebang while still relying on bash-only features like arrays or [[ ]], which fails on systems where /bin/sh is a different, stricter shell.
  2. Assuming [[ ]], arrays, local, and += are available everywhere; they are bash extensions, not part of POSIX sh.
  3. Hardcoding #!/bin/bash and assuming bash is always at that exact path; #!/usr/bin/env bash is more portable across systems where bash lives elsewhere.
Chapter Summary
  • #!/usr/bin/env bash finds bash wherever it is on the PATH, which is more portable than hardcoding #!/bin/bash.
  • Arrays, [[ ]], local, string manipulation like ${var//a/b}, and namerefs are bash-isms not guaranteed in POSIX sh.
  • If a script must run under plain sh, stick to [ ] (single bracket), avoid arrays, and use case instead of bash-only pattern matching.
  • Running shellcheck with the correct --shell target helps catch accidental bash-isms in a script meant to be POSIX-compliant.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.