Rate this page

Flattr this

Persistently set the value of an environment variable for a given user

Tested on

Debian (Etch, Lenny, Squeeze)
Ubuntu (Hardy, Intrepid, Jaunty, Karmic, Lucid, Maverick, Natty, Oneiric, Precise)

Objective

To persistently set the value of an environment variable for a given user

Background

Environment variables are name-value pairs that can be used to communicate information from a process to its descendants. They are typically used to provide programs with information about the environment in which they are executing (hence the name). Notable ones include:

DISPLAY the local or remote X Window display that should be used by default
PATH the list of paths to search when looking for an executable
PWD the current working directory
TERM the terminal type
TZ the default timezone

Environment variables are inherited from parent to child when new processes are created. Processes can freely alter their own environment variables but not those of other processes. In particular, changes made by a child process do not propagate back to its parent.

Scenario

Suppose that your username on a given machine is falken. You want to direct any HTTP requests initiated by yourself via a proxy server listening on port 8080 of proxy.example.com. This can be achieved for many (but not all) HTTP client programs by setting the environment variables http_proxy and HTTP_PROXY to http://proxy.example.com:8080/.

(The lower case variant http_proxy is the more widely accepted form, and some HTTP clients accept either, but for maximum coverage it is better to set both.)

You do not have administrative rights over the machine, and in any event do not wish to affect the environment seen by other users.

Method

On most Linux-based systems, the first instance of the shell created following a user login will look for a file called ~/.profile, and if it exists and is readable then it will execute the content of that file as shell script. Importantly it does this without spawning a child process, making ~/.profile a suitable location for setting environment variables.

(A tilde character at the start of a pathname is expanded by the shell to the home directory of the current user, so in this instance ~/.profile might correspond to /home/falken/.profile. More generally, the location of the home directory is defined by the environment variable HOME.)

Here is an example containing the required variable assignments:

export http_proxy='http://proxy.example.com:8080/'
export HTTP_PROXY="$http_proxy"

Note that because of the manner in which this file is executed by the shell there is no need for it to begin with a shebang line (for example, #!/bin/sh).

The value of HTTP_PROXY has been defined in terms of http_proxy so that changes can be made by editing one line rather than two. The use of single quotation marks in the first assignment causes interpolation to be suppressed, with the result that only single quotation marks within the URL need be escaped. The double quotation marks in the second assignment allow interpolation (which is wanted) but suppress tokenisation (which is not). In this particular example the quotation marks could be omitted because there are no special characters, but it is good practice to quote to protect against future changes.

Limitations

ssh

The content of ~/.profile is executed only when a login shell is created. One situation where this does not occur is when OpenSSH is used to execute a command non-interactively, for example:

ssh falken@wopr.mil 'env'

It is possible to work around this by explicitly creating a login shell as part of the remote command:

ssh falken@wopr.mil 'sh -l -c env'

sudo

Similar considerations apply when executing commands using sudo, even if you start an interactive shell using the -s option. To obtain a login shell you can use the -i option instead.

cron

Command run from a crontab do not execute within a login shell. As with ssh you can work around this by explicitly creating a login shell:

* * * * * sh -l -c /home/falken/myscript.pl

LTSP

Some versions of LTSP (the Linux Terminal Server Project) create sessions without creating a login shell, therefore ~/.profile is not executed. The suggested workaround is to use ~/.bashrc, which is not entirely satisfactory for the reasons discussed below.

Other methods of command execution

This is not an exhausive list of ways in which ~/.profile can be bypassed, and it would be unwise to rely on the method described here without first testing it under the particular set of circumstances in which it will be used.

Testing

You can check that the environment variable has been exported with the intended value by inspecting it from within a new login shell. The login shell can be created using the -l option of the sh command. The value can be inspected using the printenv command if it is available:

sh -l -c 'printenv http_proxy'

or the printf command if not:

sh -l -c 'printf "%s\n" "$http_proxy"'

Alternatives

Using ~/.pam_environment

On systems that use the pam_env PAM module (which most general-purpose Linux-based systems do), the file ~/pam_environment can be used to set environment variables during login. It should contain a list of name-value pairs, one per line with an equals sign between each name and value. It is not interpreted as a shell script. To set the http_proxy and HTTP_PROXY variables as described above, suitable content would be:

http_proxy=http://proxy.example.com:8080/
HTTP_PROXY=http://proxy.example.com:8080/

As with ~/.profile there are some circumstances where this file is not used, but there are differences as to what those circumstances are. For example:

Support for ~/.pam_environment is not required by the LSB (as of version 4.1), but support is widespread and not restricted to Linux-based systems. Generally it is a reasonable alternative to ~/.profile on systems that support it.

Using ~/.bashrc

The file ~/.bashrc is executed at startup by most interactive instances of the Bash shell that are not login shells. This makes it potentially useful for filling gaps in the coverage of ~/.profile. Points to bear in mind:

Using separate assignment and export statements

Some non-POSIX compatible shells lack support for the combined assignment and export command used above and instead require that these two operations be performed separately, for example:

http_proxy="http://proxy.example.com:8080/" ; export http_proxy

Scripts that use the combined form are acceptably portable for most purposes, it being reasonable to assume that the default shell is POSIX-compatible, but if you want to support the widest possible range of execution environments then there is some benefit in using separate commands.

See also

Tags: environment | shell