Newsgroups: comp.unix.shell From: Stephane CHAZELASSubject: Re: how to write portable shell scripts? References: >1120030541.202806.109050@g43g2000cwa.googlegroups.com< Message-ID: >slrndc4o2s.6fu.stephane.chazelas@spam.is.invalid< Content-Type: text/plain; charset=iso-8859-15 Content-Transfer-Encoding: 8bit User-Agent: slrn/0.9.8.1 (Debian) Date: Wed, 29 Jun 2005 09:48:28 +0100
2005-06-29, 00:35(-07), Ralph A. Moeritz:
[...]
> I'd like to make my scripts as portable as possible, since I fear
> they may have to run on scary systems like an old SCO OpenServer
> box. I have tried to restrict myself to features described in the
> FreeBSD-5.4 sh(1) manpage, which claims to be (mostly) POSIX.2
> compliant.
>
> Does anybody have some advice on portability, or common traps,
> caveats & pitfalls for certain shells etc? The point is that I
> may not be the administrator of the machine in question, in
> which case I can't simply install bash :-(
[...]
There are some useful hints in the autoconf documentation.
FreeBSD sh is not the Bourne shell, it's POSIX conformant (sort
of). You may need Bourne compatibility. /bin/sh on Solaris is
one, but as its code has just been released, you can download it
and compile it now for Linux
(http://heirloom.sourceforge.net/sh.html).
Your biggest problems will probably be on the utilities. Never
rely on GNU documentation as their tools have plenty of
non-standard features. You may want first to try to be POSIX
conformant (except for the shell syntax as you want Bourne
compatibility) as there's a text you can rely on
(http://www.opengroup.org/onlinepubs/009695399/toc.htm) and then
try to fix the problems for non-POSIX systems (Solaris is
supposed to be POSIX, but it is not by default, so you can
consider it as a non-POSIX system as far as portable shell
scripting is concerned).
compatibility issues I know about (I'm not taking the
non-standard GNU features into account) are:
- echo (the \t \n, \c, the -e/-n options)
- awk (two main variants: the old and new one, and a third:
the POSIX standard) and even then various incompatibilities
(see shelldorado)
- basename (the second argument is sometimes a regexp)
- cat (for its options)
- cd/pwd (no -P -L in some shells)
- command (not in Bourne)
- bc/dc: various problems
- dd (iseek vs skip)
- export (has a special command line parsing in some shells
like bash). Anyway for Bourne, you need
var=value; export var (or var=value export var)
- dirname (some bugs)
- find, plenty of issues and bugs
- getopts not always there
- grep (egrep vs grep -E, issues with -q/-s, regexp
incompatibilities)
- head/tail (-12 vs -n 12)
- id (don't rely on any of the options nor on the output
format).
- kill, trap (may not recognize the signal names and the
signal numbers are different from one shell to another)
- ln (don't rely on -sf or -fs)
- ls (don't rely on the output format, problems with the -g
option and more)
- mkdir (not sure about this but I think not all versions
recognize -p)
- mkfifo: not all systems support fifos. some need mknod p
- od (two variants with different option sets)
- tar (no compatibility for the options nor the produced
format).
- printf (not in very old systems, problems with %c, with \xxx)
- ps (different variants)
- read (-r not portable, different behaviors wrt IFS)
- return (different behaviors for sourced files)
- "." (wrt to arguments)
- sed: see the sed FAQ
- set: set -- with no arguments different behaviors
hence the set x ...; shift instead.
- sh -c 'inline-script' foo bar, and foo being either in $0
or $1
- sort (-k 1 vs +0)
- stty: cbreak/-icanon
- test: -h/-e/-L non-portable. Don't pass it more that 3
arguments. For three arguments, use "x$a" = "x$b".
[ 010 -gt 9 ] is sometimes false as 010 is octal for 8.
- touch: different ways to give the time.
- tr: \12 vs \n, [a-z] vs a-z...
- trap: ensure the first argument don't look like a number of
a signame. don't rely on the trap on 0/EXIT
- type: no standard output format, you can't rely on the exit
status.
- unset not always there.
- xargs: input format syntax different from implementation to
implementations (wrt quoting)
- "--" to separate options from arguments not recognized on
old system utilities, you have to ensure the arguments don't
look like options
- TZ, LC_*/LANG and various other environment variables have
an influence on some utility behavior
- many bugs in many shells (especially the ksh based) you may
have to work around.
- don't try to do anything fancy with IFS
- no trap in functions.
- some ksh optimisations have nasty side effects
- use a newline rather that a ";" before then/do.
- when using backtiks (`...`) use intermediate variables as
var=`...`; cmd "$var".
- "$@" when there's no argument resolves to 1 empty argument
rather than no arguments. use ${1+"$@"} to work around (that
doesn't work for zsh based sh, see autoconf doc)
- a redirection or pipe always involves a subshell in Bourne
(except for "exec").
- no function support in very very old shells.
That's far from being exhaustive, I'm afraid.
--
Stéphane