Ubuntu – How to write a portable shell script with error handling

bash

I have had relatively good success at writing portable, full-featured shell
shell scripts by using /bin/sh, for example:

#!/bin/sh
trap 'echo "Error on line $LINENO"; exit 1' ERR
while read LINE
do
  echo "+ $LINE"
done < file.txt

this works on BSD because /bin/sh is typically an alias to ksh

$ ls -li /bin/{sh,ksh}
26768 -r-xr-xr-x  3 root  bin  418612 Jun 18 17:41 /bin/ksh
26768 -r-xr-xr-x  3 root  bin  418612 Jun 18 17:41 /bin/sh

While on MacOS and many Linux distros simply symlink /bin/sh to bash

$ ls -li /bin/{sh,bash}
17170438 -rwxr-xr-x 1 root root 938832 Jul 18  2013 /bin/bash
17170540 lrwxrwxrwx 1 root root      4 Feb 19 12:42 /bin/sh -> bash

If these two conditions are true then I can use a relatively rich feature set common to both KSH and BASH. On Ubuntu the default shell only supports POSIX features. Is it still possible to write a cross-platform shell script that also incorporates error handling?

Edit (2014-08-18)

The solution I came up with was to auto-upgrade the script if the given shell doesn't understand the ERR trap

#!/bin/sh
trap 'echo "Error on line $LINENO"; exit 1' ERR || exec bash $0 "$@"

This allows me to write reasonably portable shell scripts that only require bash if the default shell doesn't support KSH features.

Best Answer

If you want to write a portable shell script you should stick with POSIX as that's the most reliable standard in the Unix world.

Relying in /bin/sh being anything but a Bourne shell is bad style and will likely break sooner or later.

As POSIX doesn't support the ERR trap you have to manually add your error handler to any command you want it for, using ||. For example:

#!/bin/sh

error(){
 echo "Error at $1"; exit 1   ## we don't have $LINENO in POSIX
}

while read LINE
do
  echo "+ $LINE"
  false
done < file.txt || error "while loop"
Related Question