415

Questions about

  • setting environment variables
  • the PATH

are very common here, and in most cases the answers are very similar to each other. In the future it would be nice to have a good Q/A for this.

So the question is: What are environment variables, like the executable PATH, and how can I change and use them on major operating systems?

A good answer would include a simple explanation of what environment variables and especially PATH mean to the OS, as well as simple guidelines on how to set and read them accordingly.

Daniel Beck
  • 111,893
slhck
  • 235,242

6 Answers6

397

What are Environment Variables?

Environment variables hold values related to the current environment, like the Operating System or user sessions.

Path

One of the most well-known is called PATH on Windows, Linux and Mac OS X. It specifies the directories in which executable programs* are located on the machine that can be started without knowing and typing the whole path to the file on the command line. (Or in Windows, the Run dialog in the Start Menu or Win+R).

On Linux and Mac OS X, it usually holds all bin and sbin directories relevant for the current user. On Windows, it contains at least the C:\Windows and C:\Windows\system32 directories — that's why you can run calc.exe or notepad.exe from the command line or Run dialog, but not firefox.exe. (Firefox is located in C:\Program Files\Mozilla Firefox. For information on how to include Firefox, go here.)

For example, typing calc (the .exe can be omitted) in the command line on Windows will start up the Windows Calculator.

* You can add support for file extensions other than .exe by editing %PATHEXT%.

Other

Other variables might tell programs what kind of terminal is used (TERM on Linux/Mac OS X), or, on Windows, where the Windows folder is located (e.g., %WINDIR% is C:\Windows).

Creating new environment variables

In Windows, Linux and Unix, it's possible to create new environment variables, whose values are then made available to all programs upon launch.

You can use this when writing scripts or programs that are installed or deployed to multiple machines and need to reference values that are specific to these machines. While a similar effect can be achieved using program-specific configuration settings, it's easier to do this using an environment variable if multiple programs need to access the same value.

 

Windows

GUI

  1. Open Control Panel » System » Advanced » Environment Variables.

  2. Type control sysdm.cpl,,3 in the Run dialog (Win+R) and click Environment Variables.
    For editing user variables you can also type

    %windir%\System32\rundll32.exe sysdm.cpl,EditEnvironmentVariables
    

    in the Run dialog.

  3. Right-click (My) Computer and click on Properties, or simply press Win+Break.

    • In XP click on Advanced » Environment Variables.
    • In Vista+ click on Advanced system settings » Environment Variables.
  4. There are many other ways of reaching the same place, such as by typing "environment variables" in the Start Menu/Screen search box and so on.

Environment variables in Windows are separated into user and machine/system specific values. You can view and edit their values there. Their current values upon launch are made available to all programs.

There is also Rapid Environment Editor, which helps setting and changing environment variables in Windows without the need to go deep into the system settings. Another open source program for Windows with which the path environment can be edited very conveniently is Path Editor.

Command Line

Format

Environment Variables in Windows are denoted with percent signs (%) surrounding the name:

%name%

echo

To display an environment variable's value in cmd.exe, type echo %name%.

C:\>echo %USERPROFILE%
C:\Users\Daniel

set

To create/set a variable, use set varname=value:

C:\>set FunnyCatPictures=C:\Users\Daniel\Pictures\Funny Cat Pictures

C:\>set FunnyCatPicturesTwo=%USERPROFILE%\Pictures\Funny Cat Pictures 2

To append/add a variable, use set varname=value;%varname%:

C:\>set Penguins=C:\Linux

C:\>set Penguins=C:\Windows;%Penguins%

C:\>echo %Penguins%
C:\Windows;C:\Linux

Environment variables set in this way are available for (the rest of) the duration of the Command Prompt process in which they are set, and are available to processes that are started after the variables were set.

setx

To create/set a variable permanently, use setx varname "value":

C:\>setx FunnyCatPictures "C:\Users\Daniel\Pictures\Funny Cat Pictures"

[Restart CMD]

C:\>echo %FunnyCatPictures%
C:\Users\Daniel\Pictures\Funny Cat Pictures

Unlike set, there is no equals sign and the value should be enclosed in quotes if it contains any spaces. Note that variables may expand to a string with spaces (e.g., %PATH% becomes C:\Program Files), so it is best to include quotes around values that contain any variables.

You must manually add setx to versions of Windows earlier than Vista.
Windows XP Service Pack 2 Support Tools

List of Windows Environment Variables

Here is a list of default environment variables, which are built into Windows. Some examples are: %WINDIR%, %SystemRoot%, %USERPROFILE%, and %APPDATA%. Like most names in Windows, these are case-insensitive.

 

Unix derivatives (FreeBSD, GNU / Linux, OS X)

Environment Variables in Linux are prefixed with a dollar sign ($) such as $HOME or $HOSTNAME. Many well-known and standard variables are spelled out in capital letters to signify just that. Keep in mind that variable names are case-sensitive, meaning that $User and $USER are entirely unrelated from the shell's point of view.

Unix derivatives define system wide variables in shell scripts located mostly in the /etc folder, but user-specific values may be given to those variables in scripts located in the home folder (e.g., /etc/profile, $HOME/.bash_profile). The .profile file in the home folder is a common place to define user variables.

Setting variables

These files are regular shell scripts and can contain more than just environment variable declarations. To set an environment variable, use export. To show your currently defined environment variables in a terminal, run env.

The export command is a standard way to define variables. The syntax is very intuitive. The outcome is identical for these two lines, but the first alternative is preferable in case portability to pre-POSIX Bourne shell is necessary.

var=value; export var
export var=value

The C shell and its descendants use a completely different syntax; there, the command is setenv.

See the Linux documentation project, Path HOWTO for a more thorough discussion on this topic.

Perhaps contrary to common belief, OS X is more "Unix" than Linux. Additionally to the files already mentioned, $PATH can be modified in these files:

  • /etc/paths contains all default directories that are added to the path, like /bin and /usr/sbin.
  • Any file in /etc/paths.d — commonly used by installers to make the executable files they provide available from the shell without touching system-wide or user-specific configuration files. These files simply contain one path per line. e.g., /Programs/Mozilla/Calendar/bin.

 

External Links:

Environment Variables in XP
Windows XP Service Pack 2 Support Tools (Includes setx)
Environment Variables in Windows Vista and Windows 7
Adding executables to the Run Dialog Box
Mac OSX Tips - Setting Environment Variables
TLDP: Path Howto

Mokubai
  • 95,412
Daniel Beck
  • 111,893
82

This post is from a more technical point of view than Daniel's, but doesn't explain as much the concepts.


The Wikipedia article is also an excellent referrence.

Linux and most BSDs

In most command-line shells, temporary environment variables are set using export (sh, bash, zsh) or setenv (csh, tcsh) commands.

  • Examples for prepending $HOME/bin to $PATH in bash or zsh:

    export PATH="$HOME/bin:$PATH"
    

    (In this particular case, export is unnecessary since PATH is already part of the environment.)

  • csh, tcsh:

    setenv PATH "$HOME/bin:$PATH"
    

Persistent environment variables can be set during several separate stages:

  • Login:

    • Login session setup: Linux pam_env, which usually reads from /etc/environment

    • Terminal logins: The shell's "profile" files.

      • bash uses /etc/profile and the first one of: ~/.bash_profile, ~/.bash_login, ~/.profile. Manual page bash(1) section Invocation.

        Often, the user's profile file includes an explicit call for ~/.bashrc too.

      • zsh: Manual page zsh(1) section Startup/shutdown files.

      • csh and other shells: See apropriate manual pages.

    • Graphical logins: Not sure; may vary depending on login manager. GDM appears to read ~/.profile in my system.

  • Opening of a terminal window:

    • bash uses /etc/bash.bashrc and ~/.bashrc.

Windows NT series

  • In Command Prompt (cmd.exe), use set name=value to change environment variables for that window.

    To append c:\bin to %PATH%, use:

    set path=%path%;c:\bin
    

    This only affects that cmd.exe process, and any new processes launched from it.

  • To make persistent changes, use Control Panel → System → Advanced → Environment Variables. (docs)

    Note: While user settings normally override system ones, PATH variable is handled specially: both system and user settings are merged into the final value.

    Changes are stored to Registry (see below), and apply instantly to all new processes created by Explorer (the graphical shell), for example, through Start Menu.

  • System-wide environment variables are kept in the Registry, HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment, and loaded at system boot.

    User environment is kept in HKCU\Environment and loaded during user logon.

  • By default, the system also looks for set commands in AUTOEXEC.NT file.

MS-DOS, 16-bit Windows, Windows 9x series

  • In MS-DOS Prompt (command.com), use set name=value, as in WinNT.

    Similarly, running set interactively only affects that one command.com instance, along with any new processes launched from it.

  • To make persistent changes, add or edit apropriate set lines in C:\AUTOEXEC.BAT, then reboot.

    • Workaround to avoid restarting, for Windows 9x: open a MS-DOS Prompt window, set the apropriate variables, close existing Explorer process (Start → Shut Down → while holding Ctrl+Shift, click Cancel), run explorer.exe from the MS-DOS Prompt window.

VMS

(Couldn't resist.)

DCL has no concept of "path", but various symbol and command definitions can be put in SYS$LOGIN:LOGIN.COM.

studiohack
  • 13,477
grawity
  • 501,077
12

Q: WHAT are Environment Variables ?

A: Environment Variables are similar to variables in any programming language. In the case of Windows or Unix systems they are storing various values to allow for programs and tasks to get necessary OS information or 'Environment' information. For example:

USERPROFILE : users directory within the OS files.

MAIL : where a user's mail can be found within the OS files.

Q: WHAT is the PATH variable specifically?

A: The PATH variable sets directory paths to look in when commands are executed, both for RUN commands, and for internal calls from programs. This prevents a program from needing to know its install location to call other executable processes.

It looks to the Windows Environment System PATH variable and tests each location for the given executable. Thus adding a location to the PATH variable allows an executable to be called directly.

According to this Wikipedia article:

When a command is entered in a command shell or a system call is made by a program to execute a program, the system first searches the current working directory and then searches the path, examining each directory from left to right


Q: HOW to add a location to the PATH variable ?

A: You need to edit the variable string of the Environment Variables PATH variable to include your executable's location.

One way to do this is described here:

  1. Open the Start Menu and right click on Computer. Select Properties.
  2. Select Advanced system settings.
  3. In the Advanced tab, select Environment Variables.
  4. Select EDIT or NEW. (for PATH you most likely want to EDIT).
  5. Add your location path. e.g.: C:\wamp\bin\php\php5.5.12;

I hope this clarifies some of the confusion.

Paul V
  • 271
10

For the bash shell PATH global (non-terminal) environment variables, I follow the convention used in my Ubuntu VM installation - other shells will vary:

Caveat: The whole shell start-up sequence, which .bashrc, .profile, etc. files are sourced in which order?, when do I have to re-login to get visibility to newly defined variables, aliases, etc?, what's the difference between a login, interactive, and non-interactive shell - I do use cron?, and why when I do a . ~/.bashrc is my stupid PATH variable growing longer and longer? are the key questions that come to mind when I'm thinking of my PATH variable.

In fact, I just completely re-wrote my entire bash startup file set taking ideas from the Ubuntu and cygwin skeleton files, and here are some of my in sites:

  1. Export the PATH and other global environment variables (i.e. LD_LIBRARY_PATH) variables in the .profile;
  2. Use logic in ~/.profile to source $HOME/.bashrc if it exists;
  3. Fence execution of the ~/.bashrc with a test for interactive execution, exit otherwise;
  4. Put all the aliases, shopt's, prompt setup, history control, terminal setup, function definition, etc. (interactive related setup) in the part of ~/.bashrc that is protected to only run in interactive mode;
  5. Get rid of the other bash startup files, because their existence determines whether the control path through .profile and .bashrc works as expected. That is, unless there are specific requirements to do otherwise, remove ~/.bash_profile & ~/.bash_login;
  6. When I'm at the bash prompt, and I need to update some default setup, I edit my ~/.bashrc file, then simply source it with a . ~/.bashrc to get those changes in my current shell.
  7. When I make a change to an environment variable like PATH, I need to modify and source my ~/.profile;
  8. I put my calls to fink, port, and brew specific setups in .profile.

That's my 2 cents on this topic.

5

Windows 10, without admin account

Control Panel -> User Accounts -> User Accounts -> Change my environment variables

Note you have to click on the header "User Accounts": Note you have to click on the header "User Accounts"

Again, you have to click on the header "User Accounts": Note again you have to click on the header "User Accounts"

Change my environment variables

Environment Variables

Raf
  • 229
0

Linux environment variables behind the scenes

In this answer I want to explain how environment variable work in a bit more detail under Linux to help demystify them a bit.

It is likely that concepts will be similar in other operating systems, but I am not familiar with them.

Where are environment variables stored inside a program?

Main question: Where is the environment string actual stored?.

When you ask your operating system to launch a program, besides the path of the executable, you also tell it some extra information about how you'd like to launch it, notably:

  • what the program's environment variables?
  • what the program's command line arguments?

While starting a program, the operating system will store this extra information in the program's RAM memory itself, just like any other variable programmers have code into it, so the program can basically just access them like global variables.

Also, each running program owns their own version of its environment variables, which could be different from that of any other program.

In Linux, environment variables are stored at the top of program's virtual memory, near the command line arguments:

You could also check this by just printing out the address of different types of variables in a C program along the lines of:

#include <stdio.h>
int main(int argc, char **argv, char **env)
{
        printf("argv holds %p\n", argv);
        printf("argv[0] holds %p\n", argv[0]);
        printf("env holds %p\n", env);
        printf("env[0] holds %p\n", env[0]);
        return 0;
}

which would allow you to reconstruct the memory layout yourself.

How are environment variable set by the actual system call that starts a program?

A system call in Linux is the name of the interfaces that programs use to talk to the operating system and ask it to do things like writing to stdout and launch a new process.

The system call that starts a new process is called execv. By looking at its manual page:

man execv

we can see a few variants of the C wrappers that can be used to call the actual system call:

       int execl(const char *pathname, const char *arg, ...
                       /*, (char *) NULL */);
       int execlp(const char *file, const char *arg, ...
                       /*, (char *) NULL */);
       int execle(const char *pathname, const char *arg, ...
                       /*, (char *) NULL, char *const envp[] */);
       int execv(const char *pathname, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[], char *const envp[]);

Further down it explains how the C interfaces decide the environment variables of the new process:

e - execle(), execvpe()

The environment of the new process image is specified via the argument envp. The envp argument is an array of pointers to null-terminated strings and must be terminated by a null pointer.

All other exec() functions (which do not include 'e' in the suffix) take the environment for the new process image from the external vari‐ able environ in the calling process.

At: https://stackoverflow.com/questions/2050961/is-argv0-name-of-executable-an-accepted-standard-or-just-a-common-conventi/42291142#42291142 for example I give an example of using the execve variant to set environment variables:

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) { char argv[] = {"yada yada", NULL}; char envp[] = {NULL}; execve("b.out", argv, envp); }

I think the final syscall just takes the "array of pointers to null terminated strings" as input but it would be good to confirm.

How to set environment variables from your shell for one command?

This is highly shell dependent and was well covered at: https://superuser.com/a/284361/128124

It is worth highlighting however that under the hood, the shell is just converting the command string to an underlying execv call which does the actual work of starting the program with the desired environment variables.

How to set environment variables from configuration files to be used for all commands

See e.g.: https://stackoverflow.com/questions/532155/linux-where-are-environment-variables-stored

PATH environment variable implementation

Now let's turn our attention to the PATH environment variable in particular.

Implementation wise, some of the C wrappers mentioned in man execv implement the PATH searching. I believe this is done in userland, and that the Linux kernel takes the final resolved absolute path of the executable found only.

man execv mentions:

p - execlp(), execvp(), execvpe()

These functions duplicate the actions of the shell in searching for an executable file if the specified filename does not contain a slash (/) character. The file is sought in the colon-separated list of directory pathnames specified in the PATH environment variable. If this variable isn't defined, the path list defaults to a list that includes the directories returned by confstr(_CS_PATH) (which typically re‐ turns the value "/bin:/usr/bin") and possibly also the current working directory; see NOTES for further details.

execvpe() searches for the program using the value of PATH from the caller's environment, not from the envp argument.

If the specified filename includes a slash character, then PATH is ignored, and the file at the specified pathname is executed.

In addition, certain errors are treated specially.

If permission is denied for a file (the attempted execve(2) failed with the error EACCES), these functions will continue searching the rest of the search path. If no other file is found, however, they will return with errno set to EACCES.

If the header of a file isn't recognized (the attempted execve(2) failed with the error ENOEXEC), these functions will execute the shell (/bin/sh) with the path of the file as its first argument. (If this attempt fails, no further searching is done.)

All other exec() functions (which do not include 'p' in the suffix) take as their first argument a (relative or absolute) pathname that identifies the program to be executed.

PATH environment variable standardization

One notable standardization effort that covers the PATH environment variable is POSIX, which is followed to a large extent by Linux and Mac OS but not Windows.

https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08 covers the variable itself:

PATH

This variable shall represent the sequence of path prefixes that certain functions and utilities apply in searching for an executable file known only by a filename. The prefixes shall be separated by a <colon> ( ':' ). When a non-zero-length prefix is applied to this filename, a <slash> shall be inserted between the prefix and the filename if the prefix did not end in <slash>. A zero-length prefix is a legacy feature that indicates the current working directory. It appears as two adjacent <colon> characters ( "::" ), as an initial <colon> preceding the rest of the list, or as a trailing <colon> following the rest of the list. A strictly conforming application shall use an actual pathname (such as .) to represent the current working directory in PATH. The list shall be searched from beginning to end, applying the filename to each prefix, until an executable file with the specified name and appropriate execution permissions is found. If the pathname being sought contains a <slash>, the search through the path prefixes shall not be performed. If the pathname begins with a <slash>, the specified path is resolved (see Pathname Resolution). If PATH is unset or is set to null, the path search is implementation-defined.

Since <colon> is a separator in this context, directory names that might be used in PATH should not include a <colon> character.

There is also a page about the execv family of functions: https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html#tag_16_111 which appears to contain the same contents as man execv, talking both about PATH sarch and environment variable setting.