11. Portable Shell Programming

When writing your own checks, there are some shell-script programming
techniques you should avoid in order to make your code portable. The
Bourne shell and upward-compatible shells like the Korn shell and Bash
have evolved over the years, and many features added to the original
System7 shell are now supported on all interesting porting targets.
However, the following discussion between Russ Allbery and Robert Lipe
is worth reading:

Russ Allbery:

The GNU assumption that /bin/sh is the one and only shell
leads to a permanent deadlock. Vendors don’t want to break users’
existing shell scripts, and there are some corner cases in the Bourne
shell that are not completely compatible with a Posix shell. Thus,
vendors who have taken this route will never (OK…“never say
never”) replace the Bourne shell (as /bin/sh) with a
Posix shell.

Robert Lipe:

This is exactly the problem. While most (at least most System V’s) do
have a Bourne shell that accepts shell functions most vendor
/bin/sh programs are not the Posix shell.

So while most modern systems do have a shell somewhere that meets the
Posix standard, the challenge is to find it.

For this reason, part of the job of M4sh (see section Programming in M4sh)
is to find such a shell. But to prevent trouble, if you’re not using
M4sh you should not take advantage of features that were added after Unix
version 7, circa 1977 (see section Systemology); you should not use aliases,
negated character classes, or even unset. # comments,
while not in Unix version 7, were retrofitted in the original Bourne
shell and can be assumed to be part of the least common denominator.

On the other hand, if you’re using M4sh you can assume that the shell
has the features that were added in SVR2 (circa 1984), including shell
functions,
return, unset, and I/O redirection for builtins. For
more information, refer to http://www.in-ulm.de/~mascheck/bourne/.
However, some pitfalls have to be avoided for portable use of these
constructs; these will be documented in the rest of this chapter.
See in particular Shell Functions and Limitations of Shell Builtins.

Some ancient systems have quite
small limits on the length of the ‘#!’ line; for instance, 32
bytes (not including the newline) on SunOS 4.
However, these ancient systems are no longer of practical concern.

The set of external programs you should run in a configure script
is fairly small. See (standards)Utilities in Makefiles section ‘Utilities in Makefiles’ in The GNU Coding Standards, for the list. This
restriction allows users to start out with a fairly small set of
programs and build the rest, avoiding too many interdependencies between
packages.

There are other sources of documentation about shells. The
specification for the Posix
Shell Command Language, though more generous than the restrictive shell
subset described above, is fairly portable nowadays. Also please see
the Shell FAQs.