Next: , Previous: Slashes, Up: Portable Shell


10.9 Special Shell Variables

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, but unset is not portable (see Limitations of Builtins) and a fallback value is needed.

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.

_
Many shells reserve ‘$_’ for various purposes, e.g., the name of the last command executed.
BIN_SH
In Tru64, if BIN_SH is set to xpg4, subsidiary invocations of the standard shell conform to Posix. Autoconf-generated scripts export this variable when they start up.
CDPATH
When 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`’.

Autoconf-generated scripts automatically unset CDPATH if possible, so you need not worry about this problem in those scripts.

DUALCASE
In 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.
ENV
MAIL
MAILPATH
PS1
PS2
PS4
These 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, Autoconf-generated scripts do something like this:
          (unset ENV) >/dev/null 2>&1 && unset ENV MAIL MAILPATH
          PS1='$ '
          PS2='> '
          PS4='+ '
     

IFS
Long 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 ‘<SPC><TAB><RET>’. 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.

LANG
LC_ALL
LC_COLLATE
LC_CTYPE
LC_MESSAGES
LC_MONETARY
LC_NUMERIC
LC_TIME
Autoconf-generated scripts normally 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. However, some older, nonstandard systems (notably SCO) break if locale environment variables are set to ‘C’, so when running on these systems Autoconf-generated scripts unset the variables instead.
LANGUAGE
LANGUAGE is not specified by Posix, but it is a GNU extension that overrides LC_ALL in some cases, so Autoconf-generated scripts set it too.
LC_ADDRESS
LC_IDENTIFICATION
LC_MEASUREMENT
LC_NAME
LC_PAPER
LC_TELEPHONE
These locale environment variables are GNU extensions. They are treated like their Posix brethren (LC_COLLATE, etc.) as described above.
LINENO
Most modern shells provide the current line number in LINENO. Its value is the line number of the beginning of the current command. 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.

You should not rely on LINENO within eval, as the behavior differs in practice. Also, the possibility of the Sed prepass means that you should not rely on $LINENO when quoted, when in here-documents, or when in long commands that cross line boundaries. Subshells should be OK, though. In the following example, lines 1, 6, and 9 are portable, but the other instances of LINENO are not:

          $ cat lineno
          echo 1. $LINENO
          cat <<EOF
          3. $LINENO
          4. $LINENO
          EOF
          ( echo 6. $LINENO )
          eval 'echo 7. $LINENO'
          echo 8. '$LINENO'
          echo 9. $LINENO '
          10.' $LINENO
          $ bash-2.05 lineno
          1. 1
          3. 2
          4. 2
          6. 6
          7. 1
          8. $LINENO
          9. 9
          10. 9
          $ zsh-3.0.6 lineno
          1. 1
          3. 2
          4. 2
          6. 6
          7. 7
          8. $LINENO
          9. 9
          10. 9
          $ pdksh-5.2.14 lineno
          1. 1
          3. 2
          4. 2
          6. 6
          7. 0
          8. $LINENO
          9. 9
          10. 9
          $ 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
          3. 3
          4. 4
          6. 6
          7. 7
          8. 8
          9. 9
          10. 10
     

NULLCMD
When 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.
PATH_SEPARATOR
On 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.
PWD
Posix 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’.
RANDOM
Many 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.
status
This variable is an alias to ‘$?’ for zsh (at least 3.1.6), hence read-only. Do not use it.