Environment Variables
Almost everybody coming across this page will know a little about
environment variables: e.g., the ubiquitous $PATH
that appears
both on Unix and (DOS/)Windows systems. Online discussion in
connection with this blog post: Never use environment variables for
configuration
suggests a lot of people don’t know much more than the basics of
environment variables (for understandable reasons – hardly anybody
now does day-to-day work by composing whole programs).
Here are some notes on them:
Environment variables enable rapid, overlapped, change of program behaviour
Unlike with a configuration file, by using environment variables an executable can be invoked with different behaviour very rapidly and in an overlapped fashion.
For example the following will show current time in every timezone known to the system sequentially:
for TZ in `find /usr/share/zoneinfo/posix -type f -or -type l | sort`; do
echo $TZ `TZ=$TZ date`;
done
The same could in principle be done by changing a configuration file and invoking the program in sequence. However consider the following fragment which runs the command in parallel:
time \
find /usr/share/zoneinfo/posix -type f -or -type l | \
sort | \
xargs parallel -i env TZ={} date --
Using a configuration file to do the above would be tricky as each parallel invocation would be trying to modify the same file at the same time.
Timing output is:
real 0m2.484s
user 0m0.672s
sys 0m7.094s
confirming that processes are indeed parallel (i.e. sys > real).
Nesting / dynamical scope
Bash (and some other Unix shells) have an environment variable
$SHLVL
which contains the nesting level of the current shell,
i.e., how many times the shell has recursively started itself up to
the command at hand. This variable gives an easy insight in how
environment variables are conventionally used. Here is an example
transcript:
$> echo $SHLVL
4
$> bash
$> echo $SHLVL
5
$> exit
exit
$> echo $SHLVL
4
What we can see that when we start a new nested shell, the
$SHLVL
variable is incremented by one in the new shell, however
when we get back to the previous shell we also get back to the
$SHLVL
value.
In conventional usage environment variables are example of dynamically scoped variables see e.g. this or in CLTL nomenclature indefinite scope and dynamic extent which ends when the process in which the variable was bound exits.
Dynamically scoped variables are particularly useful for layered run-time configuration of a complex system and this is reflected in the usefulness of environment variables – they certainly are more than just simple global configuration files.