Chapter 18Lesson 04~100 minutes

Bash versus POSIX sh and Portability Tradeoffs

Portability is a runtime requirement, not a style contest. Bash can dramatically simplify robust scripts when it is available; POSIX sh provides a smaller common denominator when environments are constrained.

IntermediateSecurity & portabilityHands-on lab

Learning objectives

By the end of this lesson

  • Identify major Bash-only features.
  • Match shebang to the language used.
  • Separate shell portability from utility portability.
  • Define supported platforms and versions.
  • Prefer capability detection where useful.

1. Portability is a design target, not a moral preference

POSIX sh targets a smaller common shell language. Bash adds arrays, [[ ]], process substitution, associative maps, extended parameter expansion, and many conveniences. Choose based on deployment constraints.

Choosing a shell target
flowchart TD
  R["runtime environments"] --> Q{"Bash guaranteed?"}
  Q -->|"yes"| B["use Bash features deliberately"]
  Q -->|"no"| P["target POSIX sh subset"]

2. The shebang must match the language you wrote

#!/usr/bin/env bash
# Bash script

#!/bin/sh
# POSIX-sh-targeted script

Do not write Bash arrays under #!/bin/sh and expect consistent behavior.

3. [[ ]] is Bash-specific; [ ] is broadly portable

# Bash:
if [[ $name == api-* ]]; then
  printf 'match\n'
fi

# POSIX-style:
case $name in
  api-*) printf 'match\n' ;;
esac

4. Arrays are a major portability boundary

# Bash:
hosts=("web 1" "web2")
for host in "${hosts[@]}"; do
  printf '%s\n' "$host"
done

POSIX sh has positional parameters but no standard indexed-array type. If the data model needs arrays, Bash may be the clearer dependency.

5. Process substitution is Bash-specific

# Bash:
while IFS= read -r line; do
  printf '%s\n' "$line"
done < <(generate_data)

Portable sh often uses a pipeline or temporary file instead, but that can change variable-scope behavior.

6. source is Bash; dot is portable

# Bash:
source ./lib.sh

# POSIX:
. ./lib.sh

7. Prefer portable primitives even inside Bash when convenient

printf, case, simple functions, and direct argument passing are portable and predictable. Using Bash does not require maximizing Bash-specific syntax.

8. Shell portability and utility portability are separate

A script can use POSIX shell syntax but still depend on GNU-only sed, date, xargs, or find flags. Portability includes the external toolchain.

9. macOS, Linux, BusyBox, WSL, and Git Bash differ

Even when Bash exists, version and bundled utilities vary. macOS historically ships an older system Bash; minimal containers may use BusyBox tools; Git Bash adds a Unix-like layer over Windows. Define and test the platforms you claim to support.

10. Feature checks can be more useful than OS-name checks

if help wait 2>/dev/null | grep -q -- '-n'; then
  have_wait_n=true
else
  have_wait_n=false
fi

Detect the capability your script needs rather than assuming every version of an OS provides it.

11. Hands-on lab: identify Bash-only constructs

mkdir -p "$HOME/devops-academy/bash/chapter18/lesson04"
cd "$HOME/devops-academy/bash/chapter18/lesson04"

cat > bash-only.sh <<'EOF'
#!/usr/bin/env bash
set -u

items=("one" "two words")
for item in "${items[@]}"; do
  if [[ $item == *words ]]; then
    printf 'matched=%s\n' "$item"
  fi
done
EOF

cat > portable-style.sh <<'EOF'
#!/bin/sh

for item in one two three; do
  case $item in
    two) printf 'matched=%s\n' "$item" ;;
  esac
done
EOF

chmod u+x bash-only.sh portable-style.sh
bash bash-only.sh
sh portable-style.sh

Verification checklist

12. Knowledge check

Question 1. Are Bash arrays part of POSIX sh?

Question 2. Is source portable POSIX syntax?

Question 3. Does POSIX shell syntax guarantee utility portability?

Question 4. What is often better than checking the OS name?

13. Summary

Choose Bash when its features reduce complexity and Bash is a valid runtime dependency. Choose POSIX sh when the deployment environment requires a smaller common denominator. In either case, test the external utilities and versions in your support matrix.

14. Further reading

  • GNU Bash Reference Manual.
  • POSIX Shell Command Language specification.
  • ShellCheck portability diagnostics.
  • BusyBox and platform-specific utility documentation.
Next lesson

Dependency Checks, Version Gates, and Safe Degradation

Continue Chapter 18 by strengthening Bash trust boundaries, security assumptions, and portability guarantees.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.