[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Contrary to a persistent urban legend, the Bourne shell does not
systematically split variables and back-quoted expressions, in particular
on the right-hand side of assignments and in the argument of case
.
For instance, the following code:
case "$given_srcdir" in .) top_srcdir="`echo "$dots" | sed 's,/$,,'`" *) top_srcdir="$dots$given_srcdir" ;; esac |
is more readable when written as:
case $given_srcdir in .) top_srcdir=`echo "$dots" | sed 's,/$,,'` *) top_srcdir=$dots$given_srcdir ;; esac |
and in fact it is even more portable: in the first case of the
first attempt, the computation of top_srcdir
is not portable,
since not all shells properly understand "`..."..."...`"
.
Worse yet, not all shells understand "`...\"...\"...`"
the same way. There is just no portable way to use double-quoted
strings inside double-quoted back-quoted expressions (pfew!).
$@
The traditional way to work around this portability problem is to use `${1+"$@"}'. Unfortunately this method does not work with Zsh (3.x and 4.x), which is used on Mac OS X. When emulating the Bourne shell, Zsh performs word splitting on `${1+"$@"}':
zsh $ emulate sh zsh $ for i in "$@"; do echo $i; done Hello World ! zsh $ for i in ${1+"$@"}; do echo $i; done Hello World ! |
Zsh handles plain `"$@"' properly, but we can't use plain `"$@"' because of the portability problems mentioned above. One workaround relies on Zsh's "global aliases" to convert `${1+"$@"}' into `"$@"' by itself:
test "${ZSH_VERSION+set}" = set && alias -g '${1+"$@"}'='"$@"' |
A more conservative workaround is to avoid `"$@"' if it is possible that there may be no positional arguments. For example, instead of:
cat conftest.c "$@" |
you can use this instead:
case $# in 0) cat conftest.c;; *) cat conftest.c "$@";; esac |
${var:-value}
sh
, don't accept the
colon for any shell substitution, and complain and die.
${var=literal}
: ${var='Some words'} |
otherwise some shells, such as on Digital Unix V 5.0, will die because of a "bad substitution".
Solaris' /bin/sh
has a frightening bug in its interpretation
of this. Imagine you need set a variable to a string containing
`}'. This `}' character confuses Solaris' /bin/sh
when the affected variable was already set. This bug can be exercised
by running:
$ unset foo $ foo=${foo='}'} $ echo $foo } $ foo=${foo='}' # no error; this hints to what the bug is $ echo $foo } $ foo=${foo='}'} $ echo $foo }} ^ ugh! |
It seems that `}' is interpreted as matching `${', even though it is enclosed in single quotes. The problem doesn't happen using double quotes.
${var=expanded-value}
default="yu,yaa" : ${var="$default"} |
will set var to `M-yM-uM-,M-yM-aM-a', i.e., the 8th bit of each char will be set. You won't observe the phenomenon using a simple `echo $var' since apparently the shell resets the 8th bit when it expands $var. Here are two means to make this shell confess its sins:
$ cat -v <<EOF $var EOF |
and
$ set | grep '^var=' | cat -v |
One classic incarnation of this bug is:
default="a b c" : ${list="$default"} for c in $list; do echo $c done |
You'll get `a b c' on a single line. Why? Because there are no spaces in `$list': there are `M- ', i.e., spaces with the 8th bit set, hence no IFS splitting is performed!!!
One piece of good news is that Ultrix works fine with `: ${list=$default}'; i.e., if you don't quote. The bad news is then that QNX 4.25 then sets list to the last item of default!
The portable way out consists in using a double assignment, to switch the 8th bit twice on Ultrix:
list=${list="$default"} |
...but beware of the `}' bug from Solaris (see above). For safety, use:
test "${var+set}" = set || var={value} |
`commands`
For instance, if you wanted to check that cd
is silent, do not
use `test -z "`cd /`"' because the following can happen:
$ pwd /tmp $ test -n "`cd /`" && pwd / |
The result of `foo=`exit 1`' is left as an exercise to the reader.
$(commands)
$ showrev -c /bin/sh | grep version Command version: SunOS 5.8 Generic 109324-02 February 2001 $ echo $(echo blah) syntax error: `(' unexpected |
nor does IRIX 6.5's Bourne shell:
$ uname -a IRIX firebird-image 6.5 07151432 IP22 $ echo $(echo blah) $(echo blah) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |