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, 2014 at 14:20
  • 3
    This question is perfectly on topic.
    – Seth
    Aug 11, 2014 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, 2014 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, 2014 at 13:17

1 Answer 1

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" May 10, 2017 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.