Version 13 of env

Updated 2004-10-29 14:53:44 by lwv

The env array is one of the magic names created by Tcl to reflect the value of the invoker's environment; that is to say, when one starts Tcl, what one does is make a request to the operating system to start a new process. If the process is being started directly, that process is typically given a set of variables called environment variables which reflect certain default values. When Tcl starts, it creates the env array and reads the environment. Each environment variable becomes a key in this array whose value is the value of the environment variable.

For instance, on Unix, one will typically find keys like

  • PATH : series of file system directory prefixes, typically separated by :, which the operating system will apply when asked to execute a file with an incomplete pathname.
  • HOME : name of the user's login directory.
  • LANG : string used to specify internationalization info.

To access the env array within a Tcl proc, one needs to tell the proc that env is a global array. There are two ways to do this.

  • $::env(PATH)
  • global env ; puts $env(PATH) can alternatively used to identify that the variable is globally available; however, you have to remember to use the global command in EVERY proc that you need to use env. Using the $::env notation is shorter.

The variables that appear in $::env are only those variables which the parental shell places into the environment. Under bash/ksh/sh this is done by a line such as:

 MYVAR="this is a test" ; export MYVAR

while in csh/tcsh, you do it like this:

  setenv MYVAR "this is a test"

Shell variables set but not put into the environment are not accessible by child processes.

Also note that while a Tcl program can set new variables or values in $::env , those values will NOT be reflected in the program's parent process.

This separation of process data is an intentional part of the various operating systems available today. To communicate new variables or variable values back into the parent, one needs some sort of out of band communication of information; perhaps writing a shell script or file of data which the parent shell then reads.

DKF - Additional notes

The env array is precisely the environment variables of the current process. If you want to pass a variable to a child process, setting it in env is the way to do it. And on Windows, you can't set an environment variable to an empty string, as the OS defines that to be the same as removing the variable completely. (Stupid, but that's the way things are, and working around it - which is possible BTW - is not a good idea as it can cause trouble for some programs to receive empty env-vars when they don't expect it. Keeping the tight binding is thought to be a better idea.)

There is only one env array per process. All interpreters in all threads see the same data (though IIRC safe interpreters don't see the env array at all) and a change made by one can be seen by all. This makes access to the array quite slow, and I don't recall if there are cross-interpreter/cross-thread traces (though I suspect not, so you can't use it as an inter-thread communication mechanism. Use something designed for the task instead).

LV How does one code a check to see if an environment variable like DISPLAY is available? When I code:

 if { [info exists $::env(DISPLAY) ] } {
        package require Tk

the application ceases because the variable doesn't exist.

escargo This might be a question I can answer. Your code is doing two things:

  1. Retrieving the value of env(DISPLAY) in the global name space.
  2. Checking to see if the value exists.

You are working too hard. This code just checks to see if the (array) variable exists. (It does not check the value. I suppose to be air tight somebody needs to check to ensure that the value of DISPLAY is of the form expected by X Windows. For that matter, is the value of DISPLAY set on the MacOS/MacOS X or Microsoft Windows? Or maybe your code is not intended to run cross platform.)

 if { [info exists ::env(DISPLAY) ] } {
        package require Tk

How does one actually change an environment variable with Tcl, so that the change is reflected in the program's parent process/ parental shell in Windows?

LV I don't do much on Windows, but most environments do not allow a child to modify a parent process (perhaps for security reasons, but certainly for stability reasons you don't want this to happen). About the best you could do is have the child write out a file that the parent, upon completion of the child, executes in its own process space to effect the change.

More on this subject appears in "Setting environment variables with a script".

Tcl Syntax Help