I tried to summarize the thread, and here is my proposal. Comments
are welcome, suggestions are most welcome :)
`expr'
No `expr' keyword starts with `x', so use `expr x"WORD" : 'REGEX''
to keep `expr' from misinterpreting WORD.
Don't use `length', `substr', `match' and `index'.
`expr' (`|')
You can use `|'. Although POSIX does require that `expr '''
return the empty string, it does not specify the result when you
`|' together the empty string (or zero) with the empty string. For
example:
expr '' \| ''
GNU/Linux and POSIX.2 return the empty string for this case, but
traditional Unix returns `0'. In the latest POSIX draft, the
specification has been changed to match traditional Unix's behavior
(which is bizarre, but it's too late to fix this). Please note
that the same problem does arise when the empty string results
from a computation, as in:
expr bar : foo \| foo : bar
Avoid this portability problem by avoiding the empty string.
`expr' (`:')
Don't use `\?', `\+' and `\|' in patterns, they are not supported
on Solaris.
The POSIX.2-1996 standard is ambiguous as to whether `expr a : b'
(and `expr 'a' : '\(b\)'') output `0' or the empty string. In
practice, it outputs the empty string on most platforms, but
portable scripts should not assume this. For instance, the QNX
4.2.5 native `expr' returns `0'.
You may believe that one means to get a uniform behavior would be
to use the empty string as a default value:
expr a : b \| ''
unfortunately this behaves exactly as the original expression, see
the ``expr' (`:')' entry for more information.
Older `expr' implementations (e.g. SunOS 4 `expr' and Solaris 8
`/usr/ucb/expr') have a silly length limit that causes `expr' to
fail if the matched substring is longer than 120 bytes. In this
case, you might want to fall back on `echo|sed' if `expr' fails.
Don't leave, there is some more!
The QNX 4.2.5 `expr', in addition of preferring `0' to the empty
string, has a funny behavior wrt exit status: it's always 1 when
the parenthesis are used!
$ val=`expr 'a' : 'a'`; echo "$?: $val"
0: 1
$ val=`expr 'a' : 'b'`; echo "$?: $val"
1: 0
$ val=`expr 'a' : '\(a\)'; echo "?: $val"
1: a
$ val=`expr 'a' : '\(b\)'; echo "?: $val"
1: 0