Martijn Dekker <
mar...@inlv.demon.nl> wrote:
> In article <559ad5a3$0$55333$b1db1813$
7946...@news.astraweb.com>,
> John Doe <john.doe@notpresent> wrote:
>
>> Is this the magic moment I need to abandon the idea of portability in
>> broader sense?
I wouldn't abandon portability. ksh and bash might predominate, but stricter
shells like ash, dash, and others are much more common than one might think.
And because of recent issues with bash, there has been, will continue to be,
and _should_ be systematic efforts to simplify and constrain shell
environments, especially in sensitive systems. Plus, of course, the default
shell on Debian is dash, not bash.
Learn how to use (and abuse) the positional parameter list, $@, and it's
interaction with the `for` statement and field splitting (i.e. $IFS).
Practice leveraging pathname expansion. And learn how to use parameter
expansion substitutions, which are immensely useful for manipulating string
without resort to sed or awk. IME these constructs, alone and in
combination, will usually suffice as a practical matter in lieu of
non-portable extensions such as arrays, brace expansion, etc. And of course
there's always eval, but I rarely resort to that hammer.
Sometimes you _will_ need to use a non-portable construct to get your job
done efficiently. But you can't be a good judge of those exigencies unless
you master the portable constructs.
FWIW, the preamble to most of my scripts starts with
set -e # strict errors
set -u # don't expand unbound variables
set -f # disable pathname expansion
set -C # noclobber
which helps to minimize bugs. But see below.
> I've done a lot of portable POSIX shell programming lately. One thing I
> quickly learned was not to rely on shell manuals first, as they
> typically make no distinction between what's standard and what's not,
> and even those that do often have inaccuracies.
>
> Instead, I quite simply use the POSIX specification directly as a
> reference manual. Anything that's specified there should be portable,
> unless there are compliance bugs in the shell you're using. Those are
> the cases where I do testing and look at the shell manuals.
>
> Start here:
>
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html
>
I keep telling other engineers that they should have a copy of the latest
POSIX/SUSv3 specification on their desktop. It's a free download, and it's
grep'able. The specification is almost always clearer and more concise, both
for the shell as well as for system C interfaces. But almost everybody is
too lazy to do this. It's very disheartening.
Here's a list of portability issues I've run into for a single script I
maintain, and which I document at the head of the script
https://github.com/wahern/luapath/blob/master/runlua
These are all related to POSIX-defined behavior, except for the shebang.
PORTING NOTES
unset) On NetBSD (confirmed up to 6.1.5) unset NAME will exit with a
failure status if no such variable is set. If errexit (set -e) is
enabled then the shell will exit. See NetBSD PR 49595.
#!) Linux and OS X permit recursive shebang execution, which some users
might wish to take advantage of. However, neither will field-split
interpreter arguments, instead passing the remainder of the shebang line
as a single positional argument. So we manually field-split any first
argument.
Solaris (confirmed 11.1), AIX (confirmed 7.1), OpenBSD (confirmed 5.5),
NetBSD (confirmed 5.1.2, 6.1.1), and FreeBSD (confirmed 9.0) will search
for the interpreter recursively, following shebang interpreter paths
until a binary interpreter is found. But they will not add each
intervening interpreter path to the positional argument list. If you
don't know the paths you cannot execute them recursively.
$@) On some BSD shells (confirmed NetBSD 5.1.2, 6.1.1, OpenBSD 5.5)
expansion of an empty $@ will wrongly trigger an error if nounset (set
-u) is in effect.
noclobber) On some BSD shells (confirmed NetBSD 5.1.2, 6.1.1) the
noclobber (set -C) option will wrongly cause redirection to /dev/null
using the redirect operator (">") to fail. Use the appending redirect
operator (">>") as a workaround.
trap EXIT) ksh88 (confirmed AIX 7.1) wrongly executes an EXIT trap when
the calling function returns, rather than when the shell exits. Note
ksh93 does not exhibit this bug.
$@ and null IFS) ksh88 (confirmed AIX 7.1) pdksh (confirmed pdksh 5.2.14)
and pdksh derivatives (confirmed OpenBSD 5.6 ksh, NetBSD 6.1 ksh) will
expand $@ as a single field if IFS is null (set but empty). As a
workaround we set IFS to a control character when juggling paths. ksh93,
bash, and ash correctly expand $@ when IFS is null.
In general I've found portable shell programming to be quite practical. The
biggest problems I've run into involve the behavior of $@ and IFS. I've made
a concerted effort to handle path names with internal whitespace, including
embedded newlines. The only _correct_ way to do this is by using an empty
IFS, plus some hackery to preserve trailing newlines in command
substitutions. pdksh derivatives in particular have subtle bugs in this
area. Combined with `set -u` they're my biggest source of headaches.