Today, you can usually find a POSIX shell on a system, and so that generally means you can script in the POSIX language (modulo running into compliance bugs).
The only problem is that /bin/sh
is sometimes not a POSIX shell. And you must hard-code the #!
line into scripts that are to behave as nice executables; you can't just ask the user to research the problem and then invoke your script as /path/to/posix/shell myscript
.
So, the trick is to use POSIX features in your script, but make the script automatically find the POSIX shell. One way to do it is like this:
#!/bin/sh
# At this point, we may be running under some old shell
# we have to tread carefully.
# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".
if ! test x$posix_shell = x ; then
# the three possible shell paths are just an example;
# please extend as necessary.
for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
if test -x $shell ; then
posix_shell=$shell
fi
done
if test x$posix_shell = x ; then
echo "no POSIX shell found"
exit 1
# or we could avoid bailing here and just fall back on /bin/sh:
# echo "falling back on /bin/sh: cross your fingers that it works"
# posix_shell=/bin/sh
fi
export posix_shell
# plain "$@" is broken in ancient shells!
# I seem to recall ${@+"$@"}: not sure if that's the right trick.
exec $posix_shell $0 ${@+"$@"} # can we count on exec in legacy shells?
fi
# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.
There are other approaches, such as code generation. Boostrap your scripts with a small script that takes a body of script files without a #! line, and adds one.
The worst possible thing you can do is to start writing entire scripts in such a way that they run on a Bourne shell from 1981. This is only necessary if you must write for a system that doesn't really doesn't have any other shell.
autoconf
andMetaconfig
(Perl,rn
) and collect all the tricks and their explanatory comments in one place. – geekosaur Mar 23 '11 at 22:01autoconf
is somewhat dry reading, Metaconfig's commentary is often quite amusing. – geekosaur Mar 23 '11 at 22:08dash
,bash
,zsh
) should be very close to POSIX conformant, AFAIK. – Mikel Mar 23 '11 at 22:11