All skills
Skillintermediate
POSIX Shell (sh) Reference Guide
POSIX sh is the portable shell specification defined by POSIX standards. Scripts written for POSIX sh should work across different Unix-like systems (bash, dash, ksh, etc.).
Claude Code Knowledge Pack7/10/2026
Overview
POSIX Shell (sh) Reference Guide
Overview
POSIX sh is the portable shell specification defined by POSIX standards. Scripts written for POSIX sh should work across different Unix-like systems (bash, dash, ksh, etc.).
Official Specification: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
Why POSIX Shell Matters
- Portability: Works across different Unix systems and shells
- Minimal dependencies: Available in minimal environments (containers, embedded systems)
- Faster: Shells like dash are faster than bash for simple scripts
- Compatibility: /bin/sh may not be bash (Ubuntu/Debian use dash)
Key Differences: sh vs bash
Features NOT Available in POSIX sh
-
Arrays
# Bash only - NOT POSIX array=(one two three) echo "${array[0]}" -
[[ ]] Test Construct
# Bash only - NOT POSIX if [[ "$var" == "value" ]]; then # POSIX sh - use [ ] if [ "$var" = "value" ]; then -
== Operator
# Bash style - NOT POSIX [ "$a" == "$b" ] # POSIX sh - use single = [ "$a" = "$b" ] -
Process Substitution
# Bash only - NOT POSIX diff <(ls dir1) <(ls dir2) -
Brace Expansion
# Bash only - NOT POSIX echo {1..10} -
function Keyword
# Bash style - NOT in original POSIX function myfunc { echo "hello" } # POSIX sh style myfunc() { echo "hello" } -
local Keyword
# Common but not in POSIX standard local var="value" # POSIX alternative: use function scope carefully # or use naming conventions _func_var="value" -
source Command
# Bash style - NOT POSIX source script.sh # POSIX sh . script.sh
POSIX Shell Syntax
Variables
# Assignment
var="value"
readonly CONST="constant"
# Reading variables
echo "$var"
echo "${var}"
# Command substitution (POSIX)
result=$(command)
# Old-style command substitution (works but deprecated)
result=`command`
# Arithmetic (POSIX way)
result=$((5 + 3))
Quoting
# Double quotes: Preserve literal value except $, `, and \\
echo "Value: $var"
# Single quotes: Preserve everything literally
echo 'Value: $var'
# Always quote variables
cp "$file" "$destination"
Control Structures
# If statement
if [ condition ]; then
# commands
elif [ condition ]; then
# commands
else
# commands
fi
# Case statement
case "$var" in
pattern1)
# commands
;;
pattern2|pattern3)
# commands
;;
*)
# default
;;
esac
# For loop
for item in list; do
echo "$item"
done
# While loop
while [ condition ]; do
# commands
done
# Until loop
until [ condition ]; do
# commands
done
Test Constructs
POSIX sh uses [ ] (also known as test command):
# String comparisons
[ "$a" = "$b" ] # Equal
[ "$a" != "$b" ] # Not equal
[ -z "$a" ] # String is empty
[ -n "$a" ] # String is not empty
# Numeric comparisons
[ "$a" -eq "$b" ] # Equal
[ "$a" -ne "$b" ] # Not equal
[ "$a" -lt "$b" ] # Less than
[ "$a" -le "$b" ] # Less than or equal
[ "$a" -gt "$b" ] # Greater than
[ "$a" -ge "$b" ] # Greater than or equal
# File tests
[ -e "$file" ] # File exists
[ -f "$file" ] # Regular file exists
[ -d "$file" ] # Directory exists
[ -r "$file" ] # File is readable
[ -w "$file" ] # File is writable
[ -x "$file" ] # File is executable
[ -s "$file" ] # File is not empty
# Logical operators
[ condition1 ] && [ condition2 ] # AND
[ condition1 ] || [ condition2 ] # OR
[ ! condition ] # NOT
[ condition1 -a condition2 ] # AND (inside test)
[ condition1 -o condition2 ] # OR (inside test)
Functions
# POSIX function definition
function_name() {
# No 'local' in strict POSIX
# Use careful scoping or naming conventions
echo "$1" # First argument
return 0 # Exit status
}
# Call function
function_name arg1 arg2
Input/Output Redirection
# Redirect stdout
command > file
# Redirect stderr
command 2> errors.txt
# Redirect both
command > output.txt 2>&1
# Append
command >> file
# Here document
cat </dev/null 2>&1; then
echo "ShellCheck is installed"
fi
7. Handle Errors
# Set errexit
set -e
# Or check manually
if ! command; then
echo "Command failed" >&2
exit 1
fi
8. Use set -u for Undefined Variables
set -u
# Now accessing undefined variables causes error
Common Portability Issues
1. echo Command
# Portable way to echo without newline
printf '%s' "text without newline"
# echo -n is not portable
echo -n "text" # Don't use in POSIX sh
# echo with backslashes
printf '%s\
' "text\ with\ tabs"
echo "text\ with\ tabs" # Behavior varies
2. Array Alternatives
# Instead of arrays, use:
# 1. Positional parameters
set -- one two three
echo "$1" # one
# 2. Delimited strings
items="one:two:three"
IFS=:
for item in $items; do
echo "$item"
done
3. String Manipulation
# POSIX parameter expansion
${var#pattern} # Remove shortest match from beginning
${var##pattern} # Remove longest match from beginning
${var%pattern} # Remove shortest match from end
${var%%pattern} # Remove longest match from end
# NOT POSIX (bash-specific)
${var/pattern/replacement}
${var,,} # lowercase
${var^^} # uppercase
4. Arithmetic
# POSIX way
result=$((a + b))
# NOT POSIX (bash-specific)
((a++))
let "a = a + 1"
5. read Command
# POSIX
while IFS= read -r line; do
echo "$line"
done < file
# Bash-specific flags to avoid:
read -p "prompt" # Not in POSIX
read -a array # Not in POSIX
read -t timeout # Not in POSIX
POSIX Parameter Expansion
${var} # Value of var
${var:-default} # Use default if var is unset or null
${var:=default} # Assign default if var is unset or null
${var:?error} # Error if var is unset or null
${var:+alternate} # Use alternate if var is set and not null
${#var} # Length of var
${var#pattern} # Remove shortest match from beginning
${var##pattern} # Remove longest match from beginning
${var%pattern} # Remove shortest match from end
${var%%pattern} # Remove longest match from end
Special Variables (POSIX)
$0 # Script name
$1-$9 # Positional parameters
${10} # Parameters beyond 9 (braces required)
$# # Number of positional parameters
$* # All positional parameters (as single word)
$@ # All positional parameters (as separate words)
$$ # Process ID of shell
$! # PID of last background command
$? # Exit status of last command
Testing for POSIX Compliance
Use checkbashisms
# Install checkbashisms (Debian/Ubuntu)
apt-get install devscripts
# Check script
checkbashisms script.sh
Use ShellCheck with sh
# Validate as sh script
shellcheck -s sh script.sh
Test with Different Shells
# Test with dash (common /bin/sh)
dash script.sh
# Test with ash
ash script.sh
# Test with ksh
ksh script.sh
Common POSIX Utilities
These utilities are standardized and safe to use in POSIX scripts:
cat,echo,printfgrep,sed,awkcut,sort,uniq,trhead,tail,wcfind,xargstest(same as[ ])cd,pwd,lscp,mv,rm,mkdirchmod,chownread,shift,set,export