Environment Variables
When you launch an executable, or run a command, the operating system spawns something called a process. A processes is a representation of a running program that Windows uses internally. We won’t go deeply into what makes up a process, but we do need to think a little about how processes are related to one another in order to make sense of the topic of this chapter.
If you think about it, the spawning of a process is typically triggered from
within another process. Launching a program from the start menu, the program
you launch is called a child process, and the desktop itself is the
parent process. When you execute a command on the Command Prompt, the
Command Prompt is the parent, and the command (say notepad
) is the child.
Going even further, the Command Prompt is a child process of Windows Console,
which is itself a child process of the desktop.
You can think of all of the processes running on your computer as residing in a hierarchy of parent-child relationships, just like these, going all the way up to a single parent process for the whole system, which is started when you first boot the computer.
The reason for bringing this up is because there is information inherited by child processes from their parents, and this information is the topic of this chapter: environment variables.
Environment Variables
There are a set of variables (exactly like the ones we discussed in the previous chapter) that constitute a process’s environment. These variables, and their values, are inherited directly from the process’s parent.
In Command Prompt, technically every variable is part of the shell’s environment.1
What this means is that any time you call set
to create a variable,
% set var=123
you are adding this variable to your shell’s environment. Any command that you
execute from within your shell will inherit and have access to this variable.
To demonstrate this with an (admittedly pretty contrived) example, try creating
a variable, and then running the cmd
command. This will launch a new Command
Prompt shell running as a child to your original one (in the same Console). Then,
try echoing the variable that you defined,
% set x=hello there
% cmd
Microsoft Windows <version>
% echo %x%
hello there
Now we’ll try the same thing in reverse. Define a new variable here, in the
child process. Then use exit
to close out of the child and return to the
parent. Try printing the variable that you defined, it should fail
% set y=goodbye now
% exit
% echo %y%
%y%
This happens because the child inherits copies of all of the variables defined
in the parent at the time of its creation, and so it can access x
. However,
any changes to the child’s environment remain in the child, and die when it is
closed. They are never propagated back to the parent. Additionally, we can verify
pretty easily that the child only gets copies by trying to change an inherited
variable, and seeing if that change is reflected in the parent,
% set x=hello there
% cmd
Microsoft Windows <version>
% set x=goodbye now
% exit
% echo %x%
hello there
Yup! As you can see, the child gets a copy of the parent’s environment, but after that point the two diverge. Any changes to the child’s environment won’t affect the parent, and likewise any future changes to the parent’s environment won’t affect the child.2
export
command.
Showing the Environment
You can see what variables are defined within your shell’s environment by
running the set
command without any arguments. This will produce a list of
all of the variables currently defined, and their current values. You’ll see
that there are quite a few!
% set
variable=value
othervariable=othervalue
...
In Windows, most of these variables and their values ultimately come from the System Registry, a centralized configuration database built into the operating system. Software that you install may add configuration variables to the registry as part of their installation, and a lot of these variables are predefined by Windows itself.
Notable Environment Variables
USERPROFILE
The first variable we’ll look at is USERPROFILE
. You can see what your
USERPROFILE
is by either finding it in the output of set
, or just echoing
it (note: just like with commands, variable names are not case sensitive in
Command Prompt, so capitalization doesn’t matter, but it is convention to use
ALL CAPS for environment variables and lowercase for local variables),
% echo %USERPROFILE%
C:\Users\douglas
This variable contains your user account’s home directory. The variable name is
a little inconveniently long, sadly, but this variable can be used to quickly return
to your home directory via cd
,
% cd %USERPROFILE%
PROMPT
The PROMPT
environment variable contains the text of your prompt, and can be
changed to configure it. As a somewhat silly example,
C:\Users\douglas>set PROMPT=this is a prompt>
this is a prompt>
There is actually a command, also called prompt
, which you can use to
customize this as well. And there are various special character sequences you
can add to the PROMPT
variable to fill in various information dynamically,
such as your current working directory, the current data and time, etc. You can
get a lot of information about prompt customization with,
% prompt /?
Have fun! You can reset your prompt to the default at any time by running the
prompt
command without arguments,
% prompt
USERNAME
This variable contains your username–pretty straightforward.
% echo %USERNAME%
douglas
PATH
The PATH
variable is one of the most important environment variables from the
perspective of using the command line shell. If you look at the contents of
this variable, you’ll see it is a semi-colon separated list of directories,
% echo %PATH%
C:\Program Files\someprog\;C:\Program Files\anotherprog\;...
These directories are the locations in which the Command Prompt will look for commands when you execute them.
You may have noticed that many programs that you have installed on your machine cannot be launched from the command line, while others can. For example, we can easily launch notepad,
% notepad afile.txt
but we cannot launch a web browser,
% vivaldi
'vivaldi' is not recognized as an internal or external command,
operable program, or batch file.
This is because the notepad.exe
file on our computer is located in one of the
directories listed in PATH
, but (in this case) vivaldi.exe
is not. Thus, it
follows that if we want to launch Vivaldi (or any other program) from the
command line, we need to locate it, and add the directory containing it to the
path.
A few chapters back, we learned how to search for files on our system, so let’s do that to locate our web browser. If you don’t know the name of the executable file for your browser precisely, you can use wildcards. Also, remember that once the search finds the file you want, you can abort it with ctrl+C (^C), rather than waiting for it to finish scanning your whole drive.
% cd C:\
% dir /s vivaldi.exe
Volume in drive C is Local Disk
Volume Serial Number is 44C6-3E83
Directory of C:\Users\douglas\AppData\Local\Vivaldi\Application
01/11/2023 09:27 1,983,336 vivaldi.exe
...
You’ll want to find the corresponding executable file, so it will likely
have a .exe extension. Once you’ve found it, you want to add the directory
containing it to your path. This can be done using set
,
% set PATH=%PATH%;<your directory here>
MAKE SURE YOU HAVE %PATH% AS PART OF THE VALUE YOU ASSIGN. This will ensure
that your new PATH
still contains all of the directories of the old one,
just with your web browser’s directory added on to it. If you forget to
do this, you’ll find that many commands will no longer work (because they
aren’t on the path anymore).
Once you’ve updated the path, you should be able to launch your web browser (or any other program) by typing the name of its executable file into the shell. Recall, as we saw with notepad originally, that you don’t need to type the extension. So in this case, I could open my browser to this website using
% vivaldi douglasrumbaugh.com
Making Changes to Environment Variables Persistent
After adding a directory to your path, you will be able to launch programs from
that directory within the current shell, and any child processes you spawn from
it. But, any other shells you launch that are not children of the current one
will not get this new value for PATH
, and so will not be able to launch those
programs.
If you want to persist the new path value, you’ll need to add it to the system
registry. There’s actually a graphical interface for doing this–if you punch
“environment variables” into Windows search it should pop right up–but you can
also do it from the command line using another command, setx
.
The setx
command allows you to permanently set values for environment variables,
so that any and all new shells that you launch will get the new value.
First, you should set up your path as we did above, to verify that your value
is correct and doesn’t break anything. If you mess it up with set
, you just
need to close the terminal and the change will be reverted. If you mess it up
with setx
, it won’t be nearly as easy to fix.
For historical reasons, setx
will only allow a maximum of 1024 characters in
the value of the variable being set. If your new path is longer than this, it
will be truncated.
If your path is relatively short, it should be fine to use this command to add a few directories to it. But once your path gets longer, it’s probably safer to just use the GUI to set it up.
Once you’re ready, you can add a directory permanently to your path with,
setx PATH %PATH%;<your directory here>
If you begin using the command line heavily, you’ll probably find that your path grows quite long on Windows. Linux tends to put all of the executables in a few common spots, whereas Windows likes to put each program in its own directory.
Presumably, a long path might hurt performance (as the shell needs to look in more places before it finds the command), but I’ve never noticed any slowdown to having a long path. If you do, one trick you can play is to put the directories containing more important programs at the beginning–the shell just does a linear scan of the directories until it finds what it is looking for, so putting your frequently used stuff at the front of the queue should speed things up.
Conclusion
In this chapter, we discussed the concept of an environment, a set of variables
inherited by each process from its parent, and how to add and edit variables
within the environment, as well as a few important environment variables from
the perspective of Command Prompt. Using this information, we discussed how to
set up new programs to be called from the command line, by adding them to the
PATH
variable.
In the next chapter, we’ll discuss files: how to write the results of a command to a file, read input from a file, and link commands together using pipelines.
-
There is one exception, which we won’t encounter in this tutorial. Variables defined between
setlocal
andendlocal
commands within a batch file are not persisted within the shell’s environment. ↩︎ -
This one is a bit harder to show with the tools we have at the moment, so you’ll have to take it on faith. I promise though, it is true! ↩︎