#!/bin/sh # sample-posix.sh: a portable POSIX shell script. # Free sample from 99helpers.com/file-types/sh # Runs in any POSIX shell: dash (Debian and Ubuntu's /bin/sh), bash, zsh in # sh mode, ksh and BusyBox ash. # Run: sh sample-posix.sh (a Celsius to Fahrenheit table) # sh sample-posix.sh -10 40 5 (from, to, step) # # The same jobs written without bash-only features: # bash POSIX sh # [[ $a == b* ]] case $a in b*) ... ;; esac # arr=(one two) set -- one two (the positional parameters) # function name { ... } name() { ... } # echo -e "a\tb" printf 'a\tb\n' # $(( x ** 2 )) $(( x * x )) # set -o pipefail not available in every sh: dash rejects it set -eu # 1. Functions: no `local` keyword in POSIX, so prefix names to avoid clashes. # Shell arithmetic is integer-only: work in tenths of a degree, then format. to_fahrenheit() { _tenths=$(( $1 * 18 + 320 )) _sign='' if [ "$_tenths" -lt 0 ]; then _sign='-' _tenths=$(( -_tenths )) fi printf '%s%d.%d' "$_sign" $(( _tenths / 10 )) $(( _tenths % 10 )) } # 2. Check that an argument is a whole number, with case and glob patterns. is_integer() { case $1 in '' | - | *[!0-9-]* | ?*-*) return 1 ;; *) return 0 ;; esac } from=${1:-0} to=${2:-100} step=${3:-10} for value in "$from" "$to" "$step"; do if ! is_integer "$value"; then printf '%s: "%s" is not a whole number\n' "${0##*/}" "$value" >&2 exit 2 fi done if [ "$step" -le 0 ]; then echo "step must be greater than 0" >&2 exit 2 fi # 3. A while loop with [ ] tests (the test command) and $(( )) arithmetic. printf '%8s %s\n' "Celsius" "Fahrenheit" c=$from while [ "$c" -le "$to" ]; do printf '%8d %10s\n' "$c" "$(to_fahrenheit "$c")" c=$(( c + step )) done