6

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.

4
  • @dan08 well, there are questions kept here, that are suitable for Ask Ubuntu far less than this one. – user280493 Aug 11 '14 at 14:20
  • 3
    This question is perfectly on topic. – Seth Aug 11 '14 at 14:43
  • @Seth While it is on topic, portability is an oft-raised issue on Unix & Linux, and (IMO) the real experts are there, so it's more on-topic there. – muru Dec 9 '14 at 7:31
  • I removed the extra wording describing set +o posix in order to stay more on topic with writing a shell script that runs on Ubuntu – eradman Dec 9 '14 at 13:17
3

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"
1
  • a neat trick to help if you can't have LINENO: die () { errnum=$1 ; shift ; lineno=$(grep -n "${FUNCNAME}[ ][ ]*${errnum}" "$0" | awk '{print $1}') ; while msg in "$@"; do printf "Error %s (line %s) : %s\n" "$errnum" "$lineno" "$msg" ; done ; } # note: $1 = in a uniq form: ex: _nnn_ (nnn being a uniq number, identifying only 1 line in your script) $2, ...=message(s), one per line errnum="$1". Use as : something || die __1234__ "something failed" "check this or that" – Olivier Dulac May 10 '17 at 11:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.