* Special Shell Variables:: Variables you should not change
* Shell Substitutions:: Test and assign
+* Limitations of Builtins:: Portable use of not so portable /bin/sh
* Limitations of Usual Tools:: Portable use of portable tools
-* Exiting from Shell Scripts:: How to exit from an autoconf shell script
Results of Tests
@menu
* Special Shell Variables:: Variables you should not change
* Shell Substitutions:: Test and assign
+* Limitations of Builtins:: Portable use of not so portable /bin/sh
* Limitations of Usual Tools:: Portable use of portable tools
-* Exiting from Shell Scripts:: How to exit from an autoconf shell script
@end menu
@node Special Shell Variables, Shell Substitutions, Portable Shell, Portable Shell
@end table
-@node Shell Substitutions, Limitations of Usual Tools, Special Shell Variables, Portable Shell
+@node Shell Substitutions, Limitations of Builtins, Special Shell Variables, Portable Shell
@subsection Shell Substitutions
A nonportable shell programming construct is
same way: there is just no portable way to use double-quoted strings
inside double-quoted backquoted expressions (Pfew!).
-@node Limitations of Usual Tools, Exiting from Shell Scripts, Shell Substitutions, Portable Shell
-@subsection Limitations of Usual Tools
+@node Limitations of Builtins, Limitations of Usual Tools, Shell Substitutions, Portable Shell
+@subsection Limitations of Shell Builtins
-The small set of tools you can expect to find on any machine can still
-find some limitations you should be aware of.
+No no, we are serious: some shells do have limitations :)
@table @asis
-@item @command{egrep}
-@cindex @command{egrep}
-The empty alternative is not portable, use @samp{?} instead. For
-instance with Digital Unix v5.0:
+@item @command{case}
+@cindex @command{case}
+Because of a bug in its @code{fnmatch}, @command{bash} fails to handle
+properly backslashes in character classes:
@example
-> printf "foo\n|foo\n" | egrep '^(|foo|bar)$'
-|foo
-> printf "bar\nbar|\n" | egrep '^(foo|bar|)$'
-bar|
-> printf "foo\nfoo|\n|bar\nbar\n" | egrep '^(foo||bar)$'
-foo
-|bar
+bash-2.02$ case /tmp in [/\\]*) echo OK;; esac
+bash-2.02$
@end example
-@command{egrep} also suffers the limitations of @command{grep}.
+@noindent
+This is extremely unfortunate, since you are likely to use this code to
+handle @sc{unix} or @sc{ms-dos} absolute paths. To workaround this bug,
+always put the backslash first:
-@item @command{grep}
-@cindex @command{grep}
-Don't use @samp{grep -s} to suppress output, because @samp{grep -s} on
-System V does not suppress output, only error messages. Instead,
-redirect the standard output and standard error (in case the file
-doesn't exist) of @code{grep} to @file{/dev/null}. Check the exit
-status of @code{grep} to determine whether it found a match.
+@example
+bash-2.02$ case '\TMP' in [\\/]*) echo OK;; esac
+OK
+bash-2.02$ case /tmp in [\\/]*) echo OK;; esac
+OK
+@end example
-Don't use multiple regexps with @samp{-e}, as some @code{grep} will only
-honor the last pattern (eg., IRIX 6.5 and Solaris 2.5.1). Anyway,
-Stardent Vistra SVR4 @code{grep} lacks @samp{-e}... Instead, use
-alternation and @code{egrep}.
+@item @command{exit}
+@cindex @command{exit}
+Some shell scripts, such as those generated by @command{autoconf}, use a
+trap to clean up before exiting. If the last shell command exited with
+nonzero status, the trap also exits with nonzero status so that the
+invoker can tell that an error occurred.
-@item @command{sed}
-@cindex @command{sed}
-@code{sed} scripts should not use branch labels longer than 8 characters
-and should not contain comments.
+Unfortunately, in some shells, such as Solaris 8 @command{sh}, an exit
+trap ignores the @code{exit} command's status. In these shells, a trap
+cannot determine whether it was invoked by plain @code{exit} or by
+@code{exit 1}. To work around this problem, use @code{(exit 1); exit}
+instead of @samp{exit 1}.
-@code{sed} input should have reasonably long lines, since some
-@code{sed} have an input buffer limited to 4000 bytes.
+@item @command{export}
+@cindex @command{export}
+The builtin @command{export} dubs @dfn{environment variable} a shell
+variable. Each update of exported variables corresponds to an update of
+the environment variables. Conversely, each environment variable
+received by the shell when it is launched should be imported as a shell
+variable marked as exported.
+
+Alas, pretty many shells, such as Solaris 2.5, IRIX 6.3, IRIX 5.2, AIX
+4.1.5 and DU 4.0 forget to @command{export} the environment variables
+they receive. As a result two variables are coexisting: the environment
+variable, and the shell variable. The following code demonstrates this
+failure:
+
+@example
+#! /bin/sh
+echo $FOO
+FOO=bar
+echo $FOO
+exec /bin/sh $0
+@end example
+
+@noindent
+when run with FOO=foo in the environment, these shells will print
+alternately @samp{foo} and @samp{bar}, although it should only print
+@samp{foo} and then a sequence of @samp{bar}s.
+
+Therefore you should @command{export} again each environment variable
+you update.
-Alternation, @samp{\|}, is common but not portable.
@item @command{test}
@cindex @command{test}
@end example
@end table
+@node Limitations of Usual Tools, , Limitations of Builtins, Portable Shell
+@subsection Limitations of Usual Tools
-@node Exiting from Shell Scripts, , Limitations of Usual Tools, Portable Shell
-@subsection Exiting from Shell Scripts
+The small set of tools you can expect to find on any machine can still
+find some limitations you should be aware of.
-Shell scripts generated by @command{autoconf} use a trap to clean up
-before exiting. If the last shell command exited with nonzero status,
-the trap also exits with nonzero status so that the invoker of autoconf
-can tell that an error occurred.
+@table @asis
+@item @command{egrep}
+@cindex @command{egrep}
+The empty alternative is not portable, use @samp{?} instead. For
+instance with Digital Unix v5.0:
-Unfortunately, in some shells, such as Solaris 8 @command{sh}, an exit
-trap ignores the @code{exit} command's status. In these shells, a trap
-cannot determine whether it was invoked by plain @code{exit} or by
-@code{exit 1}. To work around this problem, use @code{(exit 1); exit}
-instead of @samp{exit 1} to exit an autoconf script with status 1.
+@example
+> printf "foo\n|foo\n" | egrep '^(|foo|bar)$'
+|foo
+> printf "bar\nbar|\n" | egrep '^(foo|bar|)$'
+bar|
+> printf "foo\nfoo|\n|bar\nbar\n" | egrep '^(foo||bar)$'
+foo
+|bar
+@end example
+
+@command{egrep} also suffers the limitations of @command{grep}.
+
+@item @command{grep}
+@cindex @command{grep}
+Don't use @samp{grep -s} to suppress output, because @samp{grep -s} on
+System V does not suppress output, only error messages. Instead,
+redirect the standard output and standard error (in case the file
+doesn't exist) of @code{grep} to @file{/dev/null}. Check the exit
+status of @code{grep} to determine whether it found a match.
+
+Don't use multiple regexps with @samp{-e}, as some @code{grep} will only
+honor the last pattern (eg., IRIX 6.5 and Solaris 2.5.1). Anyway,
+Stardent Vistra SVR4 @code{grep} lacks @samp{-e}... Instead, use
+alternation and @code{egrep}.
+
+@item @command{sed}
+@cindex @command{sed}
+@code{sed} scripts should not use branch labels longer than 8 characters
+and should not contain comments.
+
+@code{sed} input should have reasonably long lines, since some
+@code{sed} have an input buffer limited to 4000 bytes.
+
+Alternation, @samp{\|}, is common but not portable.
+@end table
@node Multiple Cases, Language Choice, Portable Shell, Writing Tests