Next: Shell Functions, Previous: Slashes, Up: Portable Shell [Contents][Index]
Some shell variables should not be used, since they can have a deep
influence on the behavior of the shell. In order to recover a sane
behavior from the shell, some variables should be unset; M4sh takes
care of this and provides fallback values, whenever needed, to cater
for a very old /bin/sh that does not support unset.
(see Portable Shell Programming).
As a general rule, shell variable names containing a lower-case letter
are safe; you can define and use these variables without worrying about
their effect on the underlying system, and without worrying about
whether the shell changes them unexpectedly. (The exception is the
shell variable status, as described below.)
Here is a list of names that are known to cause trouble. This list is
not exhaustive, but you should be safe if you avoid the name
status and names containing only upper-case letters and
underscores.
?Not all shells correctly reset ‘$?’ after conditionals (see Limitations of Shell Builtins). Not all shells manage ‘$?’ correctly in shell functions (see Shell Functions) or in traps (see Limitations of Shell Builtins). Not all shells reset ‘$?’ to zero after an empty command.
$ bash -c 'false; $empty; echo $?' 0 $ zsh -c 'false; $empty; echo $?' 1
_Many shells reserve ‘$_’ for various purposes, e.g., the name of the last command executed.
BIN_SHIn Tru64, if BIN_SH is set to xpg4, subsidiary invocations of
the standard shell conform to Posix.
CDPATHWhen this variable is set it specifies a list of directories to search
when invoking cd with a relative file name that did not start
with ‘./’ or ‘../’. Posix
1003.1-2001 says that if a nonempty directory name from CDPATH
is used successfully, cd prints the resulting absolute
file name. Unfortunately this output can break idioms like
‘abs=`cd src && pwd`’ because abs receives the name twice.
Also, many shells do not conform to this part of Posix; for
example, zsh prints the result only if a directory name
other than . was chosen from CDPATH.
In practice the shells that have this problem also support
unset, so you can work around the problem as follows:
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
You can also avoid output by ensuring that your directory name is absolute or anchored at ‘./’, as in ‘abs=`cd ./src && pwd`’.
Configure scripts use M4sh, which automatically unsets CDPATH if
possible, so you need not worry about this problem in those scripts.
CLICOLOR_FORCEWhen this variable is set, some implementations of tools like
ls attempt to add color to their output via terminal escape
sequences, even when the output is not directed to a terminal, and can
thus cause spurious failures in scripts. Configure scripts use M4sh,
which automatically unsets this variable.
DUALCASEIn the MKS shell, case statements and file name generation are
case-insensitive unless DUALCASE is nonzero.
Autoconf-generated scripts export this variable when they start up.
ENVMAILMAILPATHPS1PS2PS4These variables should not matter for shell scripts, since they are
supposed to affect only interactive shells. However, at least one
shell (the pre-3.0 UWIN Korn shell) gets confused about
whether it is interactive, which means that (for example) a PS1
with a side effect can unexpectedly modify ‘$?’. To work around
this bug, M4sh scripts (including configure scripts) do something
like this:
(unset ENV) >/dev/null 2>&1 && unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ '
(actually, there is some complication due to bugs in unset;
see Limitations of Shell Builtins).
FPATHThe Korn shell uses FPATH to find shell functions, so avoid
FPATH in portable scripts. FPATH is consulted after
PATH, but you still need to be wary of tests that use PATH
to find whether a command exists, since they might report the wrong
result if FPATH is also set.
GREP_OPTIONSWhen this variable is set, some implementations of grep honor
these options, even if the options include direction to enable colored
output via terminal escape sequences, and the result can cause spurious
failures when the output is not directed to a terminal. Configure
scripts use M4sh, which automatically unsets this variable.
IFSLong ago, shell scripts inherited IFS from the environment,
but this caused many problems so modern shells ignore any environment
settings for IFS.
Don’t set the first character of IFS to backslash. Indeed,
Bourne shells use the first character (backslash) when joining the
components in ‘"$@"’ and some shells then reinterpret (!) the
backslash escapes, so you can end up with backspace and other strange
characters.
The proper value for IFS (in regular code, not when performing
splits) is ‘SPCTABRET’. The first character is
especially important, as it is used to join the arguments in ‘$*’;
however, note that traditional shells, but also bash-2.04, fail to adhere
to this and join with a space anyway.
M4sh guarantees that IFS will have the default value at the
beginning of a script, and many macros within autoconf rely on this
setting. It is okay to use blocks of shell code that temporarily change
the value of IFS in order to split on another character, but
remember to restore it before expanding further macros.
Unsetting IFS instead of resetting it to the default sequence
is not suggested, since code that tries to save and restore the
variable’s value will incorrectly reset it to an empty value, thus
disabling field splitting:
unset IFS # default separators used for field splitting save_IFS=$IFS IFS=: # ... IFS=$save_IFS # no field splitting performed
LANGLC_ALLLC_COLLATELC_CTYPELC_MESSAGESLC_MONETARYLC_NUMERICLC_TIMEYou should set all these variables to ‘C’ because so much configuration code assumes the C locale and Posix requires that locale environment variables be set to ‘C’ if the C locale is desired; configure scripts and M4sh do that for you. Export these variables after setting them.
LANGUAGELANGUAGE is not specified by Posix, but it is a GNU
extension that overrides LC_ALL in some cases, so you (or M4sh)
should set it too.
LC_ADDRESSLC_IDENTIFICATIONLC_MEASUREMENTLC_NAMELC_PAPERLC_TELEPHONEThese locale environment variables are GNU extensions. They
are treated like their Posix brethren (LC_COLLATE,
etc.) as described above.
LINENOMost modern shells provide the current line number in LINENO.
Its value is the line number of the beginning of the current command.
M4sh, and hence Autoconf, attempts to execute configure with
a shell that supports LINENO. If no such shell is available, it
attempts to implement LINENO with a Sed prepass that replaces each
instance of the string $LINENO (not followed by an alphanumeric
character) with the line’s number. In M4sh scripts you should execute
AS_LINENO_PREPARE so that these workarounds are included in
your script; configure scripts do this automatically in AC_INIT.
You should not rely on LINENO within eval or shell
functions, as the behavior differs in practice. The presence of a
quoted newline within simple commands can alter which line number is
used as the starting point for $LINENO substitutions within that
command. Also, the possibility of the Sed prepass means that you should
not rely on $LINENO when quoted, when in here-documents, or when
line continuations are used. Subshells should be OK, though. In the
following example, lines 1, 9, and 14 are portable, but the other
instances of $LINENO do not have deterministic values:
$ cat lineno
echo 1. $LINENO
echo "2. $LINENO
3. $LINENO"
cat <<EOF
5. $LINENO
6. $LINENO
7. \$LINENO
EOF
( echo 9. $LINENO )
eval 'echo 10. $LINENO'
eval 'echo 11. $LINENO
echo 12. $LINENO'
echo 13. '$LINENO'
echo 14. $LINENO '
15.' $LINENO
f () { echo $1 $LINENO;
echo $1 $LINENO }
f 18.
echo 19. \
$LINENO
$ bash-3.2 ./lineno 1. 1 2. 3 3. 3 5. 4 6. 4 7. $LINENO 9. 9 10. 10 11. 12 12. 13 13. $LINENO 14. 14 15. 14 18. 16 18. 17 19. 19
$ zsh-4.3.4 ./lineno 1. 1 2. 2 3. 2 5. 4 6. 4 7. $LINENO 9. 9 10. 1 11. 1 12. 2 13. $LINENO 14. 14 15. 14 18. 0 18. 1 19. 19
$ pdksh-5.2.14 ./lineno 1. 1 2. 2 3. 2 5. 4 6. 4 7. $LINENO 9. 9 10. 0 11. 0 12. 0 13. $LINENO 14. 14 15. 14 18. 16 18. 17 19. 19
$ sed '=' <lineno | > sed ' > N > s,$,-, > t loop > :loop > s,^\([0-9]*\)\(.*\)[$]LINENO\([^a-zA-Z0-9_]\),\1\2\1\3, > t loop > s,-$,, > s,^[0-9]*\n,, > ' | > sh 1. 1 2. 2 3. 3 5. 5 6. 6 7. \7 9. 9 10. 10 11. 11 12. 12 13. 13 14. 14 15. 15 18. 16 18. 17 19. 20
In particular, note that config.status (and any other subsidiary
script created by AS_INIT_GENERATED) might report line numbers
relative to the parent script as a result of the potential Sed pass.
NULLCMDWhen executing the command ‘>foo’, zsh executes
‘$NULLCMD >foo’ unless it is operating in Bourne shell
compatibility mode and the zsh version is newer
than 3.1.6-dev-18. If you are using an older zsh
and forget to set NULLCMD,
your script might be suspended waiting for data on its standard input.
optionsFor zsh 4.3.10, options is treated as an associative
array even after emulate sh, so it should not be used.
PATH_SEPARATOROn DJGPP systems, the PATH_SEPARATOR environment
variable can be set to either ‘:’ or ‘;’ to control the path
separator Bash uses to set up certain environment variables (such as
PATH). You can set this variable to ‘;’ if you want
configure to use ‘;’ as a separator; this might be useful
if you plan to use non-Posix shells to execute files. See File System Conventions, for more information about PATH_SEPARATOR.
POSIXLY_CORRECTIn the GNU environment, exporting POSIXLY_CORRECT with any value
(even empty) causes programs to try harder to conform to Posix.
Autoconf does not directly manipulate this variable, but bash
ties the shell variable POSIXLY_CORRECT to whether the script is
running in Posix mode. Therefore, take care when exporting or unsetting
this variable, so as not to change whether bash is in Posix
mode.
$ bash --posix -c 'set -o | grep posix > unset POSIXLY_CORRECT > set -o | grep posix' posix on posix off
PWDPosix 1003.1-2001 requires that cd and
pwd must update the PWD environment variable to point
to the logical name of the current directory, but traditional shells
do not support this. This can cause confusion if one shell instance
maintains PWD but a subsidiary and different shell does not know
about PWD and executes cd; in this case PWD
points to the wrong directory. Use ‘`pwd`’ rather than
‘$PWD’.
RANDOMMany shells provide RANDOM, a variable that returns a different
integer each time it is used. Most of the time, its value does not
change when it is not used, but on IRIX 6.5 the value changes all
the time. This can be observed by using set. It is common
practice to use $RANDOM as part of a file name, but code
shouldn’t rely on $RANDOM expanding to a nonempty string.
statusThis variable is an alias to ‘$?’ for zsh (at least 3.1.6),
hence read-only. Do not use it.
Next: Shell Functions, Previous: Slashes, Up: Portable Shell [Contents][Index]