How Environment Variables Work

When you launch a terminal window and the shell inside it, a collection of variables is referenced to ensure the shell is configured correctly. These variables also ensure that any information to which the terminal window and shell might need to refer is available. Collectively, these variables hold settings that define the environment you find inside your terminal window, right down to the look of the command prompt. So, naturally, they’re referred to as environment variables.

Some environment variables are system-wide, or global. Others are session-wide and can only be seen by you. Others can’t reference your session environment variables. There’s a third set of environment variables defined within the shell. Your locale, time zone, and keyboard settings, the set of directories searched when the shell tries to find a command, and your default editor, are all stored in shell environment variables.

We’re going to show you how to see the environment variables that exist on your system, and we’ll describe how to create your own. We’ll also show you how to make them available to child processes and to be persistent across reboots.

Environments and Inheritance

When a shell starts, it goes through an initialization phase. It’s at this point that it reads the environment variables that define the environment of the shell.

When a program or command is launched from that shell—known as a child process—it inherits the environment of the parent process—but watch out! As we’ll see, you can create variables that don’t get added to your environment, so they won’t be inherited by a child process.

If the child process is a shell, that shell will initialize from its own, fresh, set of variables. So, if you alter the command prompt in the current shell, and then launch a child shell, the child shell won’t inherit the modified command prompt of the parent.

Global Environment Variables

By convention, environment variables are given uppercase names. Here are some of the global environment variables, and what the values they contain represent:

SHELL: The name of the shell that will launch when you open a terminal window. On most Linux distributions, this will be bash unless you changed it from the default. TERM: Terminal windows are actually emulations of a hardware terminal.  This holds the type of hardware terminal that will be emulated. USER: The username of the current person using the system. PWD: The path to the current working directory. OLDPWD: The directory you were in prior to moving to the current working directory. LS_COLORS: The list of color codes used by the ls highlight different file types. MAIL: If the mailsystem has been set up on your Linux computer (by default, it isn’t), this will hold the path to the current user’s mailbox. PATH: A list of directories that the shell will search through to find command executables. LANG: The language, localization, and character encoding settings. HOME: The home directory of the current user. : The underscore () environment variable holds the last command that was typed.

RELATED: How to Use pushd and popd on Linux

We can see what some of these are set to using nothing more sophisticated than echo, which will write the values to the terminal window. To see the value held by an environment variable, you need to add a dollar sign ($) to the start of its name.

A nice touch is that you can use tab completion to fill in the environment variable name for you. Type a few letters of the name and hit Tab. The name of the variable is completed by the shell. If that doesn’t happen, you’ll need to type a few more letters to distinguish the environment variable from other commands with names that start with those same letters:

To create your own global environment variables, add them to the /etc/environment file. You’ll need to use sudo to edit this file:

To add an environment variable, type its name, an equal sign (=), and the value you want the environment variable to hold. Don’t space before or after the equal sign (=). The name of the environment variable can contain letters, an underscore (_), or numbers. However, the first character of a name cannot be a number.

If there are spaces in the value, be sure you enclose the entire value in quotation marks (").

Save the file, and then log out and back in again. Use echo to test that a new variable exists and holds the value you set:

Because it’s a global environmental variable, and available to everyone, user mary can reference the environment variable when she next logs in:

To see all the environment variables at once, type printenv. There’s a lot of output, so it makes sense to pipe it through sort, and then into less:

The sorted list of environment variables is displayed for us in less.

We can pipe the output through grep to look for environment variables related to a particular topic.

RELATED: How to Edit Text Files Graphically on Linux With gedit

Shell Environment Variables

These are some of the shell environment variables used in bash to dictate or record its behavior and functionality. Some of the values are updated as you use the terminal. For example, the COLUMNS environment variable will be updated to reflect changes you might make to the width of the terminal window:

BASHOPTS: The command-line options that were used when bash was launched. BASH_VERSION: The bash version number as a string of words and numbers. BASH_VERSINFO: The bash version as a digit. COLUMNS: The current width of the terminal window. DIRSTACK: The directories that have been added to the directory stack by the pushd command. HISTFILESIZE: Maximum number of lines permitted in the  history file. HISTSIZE: Number of lines of history allowed in memory. HOSTNAME: The hostname of the computer. IFS: The Internal Field Separator used to separate input on the command line. By default, this is a space. PS1: The PS1 environment variable holds the definition for the primary, default, and command prompt. A set of tokens called escape sequences can be included in the definition of your command prompt. They represent such things as the host- and username, the current working directory, and the time. PS2: When a command spans more than one line and more input is expected, the secondary command prompt is shown. The PS2 environment variable holds the definition of this secondary prompt, which, by default, is the greater than sign (>). SHELLOPTS: Shell options you can set using the set option. UID: The User Identifier of the current user.

RELATED: How to Use pushd and popd on Linux

Let’s check a few of these shell variables:

For the sake of completeness, here are the tokens you can use in the command prompt definitions:

\t: The current time, formatted as HH:MM:SS. \d: The current date, expressed as weekday, month, date. \n: A new-line character. \s: The name of your shell. \W: The name of your current working directory. \w: The path to your current working directory. \u: The username of the person who’s logged in. \h: The hostname of the computer. #: Each command within a shell is numbered. This allows you to see the number of the command in your command prompt. This is not the same as the number the command will have in the history list. $: Sets the final character of the prompt to a dollar sign ($) for a regular user, and a hash symbol (#) for the root user. This works by checking the UID of the user. If it’s zero, the user is root.

You’ll find the definition of your PS1 environment variable in your .bashrc file.

Creating Session Environment Variables

To create environment variables for your own use, add them to the bottom of your .bashrc file. If you want to have the environment variables available to remote sessions, such as SSH connections, you’ll need to add them to your .bash_profile file, as well.

The format of the environment variable definition is the same for both files. To add a definition to your .bash_profile file, type this in your home directory:

We’ve added an environment variable called INHERITED_VAR. Note the word “export” at the start of the line.

Save and close your file after you finish editing. You could log out and back in again, or you can cause the shell to re-read the .bash_profile file using the dot command (.) like this:

Now, let’s create an environment variable on the command line:

If we use echo, we can see that both environment variables are accessible to us:

You’ll notice the definition of the INHERITED_VAR environment variable had the word “export” at the start of the line. This means the environment variable will be inherited by child processes of the current shell. If we launch another one using the bash command, we can check the two variables again, from inside the child shell:

As you can see, the INHERITED_VAR is accessible in the child shell, but LOCAL_VAR is not.  We simply get a blank line.

Although “export” adds the environment variable part to the environment that child processes inherit, INHERITED_VAR is not a global environment variable. For example, user mary cannot reference it:

To close our child bash session, we use exit:

Inherited environments affect scripts, too. Here’s a simple script that writes the values of our three environment variables to the terminal window:

This was saved to a file called envtest.sh, and then made executable with the following:

When we run the script, it can access two out of three environment variables:

The script can see the WEBSITE global environment variable and the INHERITED_VAR exported environment variable. It cannot access LOCAL_VAR, even though the script is running in the same shell where the variable was created.

If we need to, we can export an environment variable from the command line. We’ll do that to our LOCAL_VAR, and then run the script again:

The environment variable has been added to the environment of the current shell, and so it appears in the environment that is inherited by the script. The script can reference that environment variable, too.

Remote Connections

Global environment variables are accessible to remote login sessions, but if you want your locally defined environment variables available to you remotely, you must add them to your .bash_profile file. You can set the same environment variable in the .bashrc and .bash_profile files, with different values. This could be picked up by a script, say, to modify its behavior for people using the system locally or remotely.

(At the risk of confusing matters, there’s also a .profile file. It can hold environment variable definitions, too. However, the .profile file is not read if the .bash_profile file is present. So, the safest thing to do—and the bash-compliant way—is to use the .bash_profile file.)

To edit the .bash_profile file, we’ll use gedit again:

We’re going to add the same environment variable with the same value we used before.

Save your changes and close gedit.

On another computer, we’ll make an SSH connection to the test computer.

Once we’re connected, we’ll run the script once more:

The .bash_profile file has been read as part of the initialization of the remote login, and the INHERITED_VAR environment variable is accessible to us and the script.

Unsetting an Environment Variable

To unset an environment variable use the unset command. If we unset the global environment variable, WEBSITE, and the exported environment variable, INHERITED_VAR, they’ll no longer be available on the command line, nor in child processes:

A point to note is this only changes the availability of global environment variables for you in this session. Another person who’s logged in simultaneously will still be able to access his instance of that global environment variable. His instance was initialized and read from the /etc/environment file during his login process, and is independent of anyone else’s copy of the variable.

As an example, user mary can still access the WEBSITE environment variable and read its value, even though user dave has unset it in his session:

Environmental Control

Environment variables can be used to let scripts and applications know how they should behave. They can be used to store settings or small amounts of data. For example, a script can populate an environment with a value that can be referenced by other scripts without having to write them to a file.