Python First

Your PATH

2026-08-01

Abstract

The PATH environment variable is often the cause of problems for those not overly familiar with the command-line. Learning how to manage the PATH environment variable, is a valuable skill. First, we shall look at environment variables in general, before we tackle PATH. Unless you prefer the TL;DR.

Environment Variables

Every process (program) gets a copy of a set of key/value pairs from its parent process, called the environment. The parent process of a program like python, could be your command-line shell, or a GUI (Graphical User Interface) shell — it depends from where you launched the Python executable.

Since a child process gets a copy, it cannot modify the parent's environment, nor the environment of any other process running, for that matter.

This environment feature is valid on all Unix-like systems as well as on Windows. How to access this environment, will depend on your operating system and command-line shell. A programming language like Python can also access this environment.

The key in the key/value pair list, is the name (or identifier) of an environment variable. The value part, is well, the value, contents, or expansion of the variable.

Inspection

First, you should probably see the ‘bigger picture’ by listing the environment.

Unix-Like Shells

We can get a list of environment variables in Unix-like shells by running the env command in your command-line shell like bash, zsh, or other shell. This will display a list of all exported environment variables. It can be a long list.

$> env

We often pipe the output of env to the grep program to filter the output. For example:

$> env | grep -e '^HOME'

This will show you all environment variables that starts with HOME, and their values. There should be only one. This will show the location of your personal home directory on Unix-like operating systems. You can also just expand a variable's value with $‹var› or ${‹var›}:

#= sh
$> echo $HOME
$> echo "My home directory is ${HOME}"

You can do the same for PATH, but may want to split it, so that each path is displayed on a separate line:

#= sh
$> echo $PATH
$> echo $PATH | tr ':' '\n'
$> echo $PATH | tr ':' '\n' > mypath.txt

The very last command-line saves the split output to a file mypath.txt. You can edit this file by adding new lines (new paths), move lines around, or delete lines. Then you can recombine these lines into a colon separated list. Optionally, you can re-assign this modified result to the original PATH variable:

#= sh
$> cat mypath.txt | tr '\n' ':' | sed 's/:$//'
$> export PATH="$(cat mypath.txt | tr '\n' ':' | sed 's/:$//')"

PowerShell

Whether you are using the legacy ‘Windows PowerShell’ or the newer, portable, ‘PowerShell 7’ also known as ‘PowerShell Core’, the environment is accessed via a provider called Env:. This means you can treat it like a drive, if you will, and use dir (an alias for Get-ChildItem) to list all the key/value pairs in the environment:

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\Users\‹user›> dir Env:

You can also use wildcard expansion to list variables. For example Env:USER* will match all environment variables starting with USER:

#= pwsh
$> dir Env:
$> Get-ChildItem Env:
$> gci Env:
$> dir Env:USER*

To expand any particular variable, you would use $Env:‹var› or ${Env:USERPROFILE} e.g., $Env:USERPROFILE or ${Env:USERPROFILE}.

#= pwsh
$> echo $Env:USERPROFILE
$> echo "My home directory is $Env:USERPROFILE"
$> echo "My home directory is ${Env:USERPROFILE}"

You can then also expand the PATH environment variable. It can be long and difficult to decipher, so you may want to split it into separate lines. You can even save these separate lines in a file, e.g., mypaths.txt, which you can edit (add, remove, change, lines or paths).

#= pwsh
$> $Env:PATH -split ';'
$> $Env:PATH -split ';' > mypaths.txt

If you modified mypaths.txt and want to change the current PATH with its contents, you can do this:

#= pwsh
$> $Env:PATH = "$(gc mypaths.txt | Join-String ';' -nn)"
$> $Env:PATH = "$(Get-Content mypaths.txt 
··   | Join-String -Separator ':' -NoNewline)

The very last command-line is just the longer version of the first which used aliases for Get-Content and Join-String. The -nn option means -NoNewline so that the result will not contain a trailing newline character.

Command Prompt

If you are unfortunate enough to use the legacy Windows Command Prompt (cmd.exe), all is not lost, since it does have access to environment variables. To run Command Prompt, you can search for it in the Windows Start Menu, or type cmd after pressing Win+R (adding .exe is allowed but not necessary). You will see something like the following banner, followed by a prompt.

Microsoft Windows [Version 10.0.19045.2728]
(c) Microsoft Corporation. All rights reserved.

C:\Users\‹user›> ▄

By default, unless customised, command-line programs on Windows will run inside a character-based console emulation window called the Windows Console (conhost.exe). The later versions can emulate a terminal, but this is not configured by default.

Typing set with no arguments, will list all the environment variables. Windows processes do not have the concept of exported versus non-exported environment variables.

To display the value of the USERPROFILE variable (your home directory), you can use:

#= cmd
$> echo %USERPROFILE%
$> echo "My home directory is %USERPROFILE%"
$> for %P in ("%PATH:;=";"%") do @echo %P
$> for %P in ("%PATH:;=";"%") do @echo %~P > paths.txt
$> set NEWPATH=
$> for /f "usebackq tokens=*" %A in (`paths.txt`) do @call ^
··    set "NEWPATH=%%NEWPATH%%;%A"
$> set "NEWPATH=%NEWPATH:~1%"

The last four command-lines will load paths listed one per line in a file paths.txt, join them together separated by semicolons (;), which is then stored in a variable NEWPATH, from which a leading semicolon is finally removed.

Windows GUI

You can also view environment variables as stored in the Windows Registry. On your Start Menu, search for ‘Edit environment variables for your account’. This will bring up a dialog box showing two lists. The upper list consists of variables for yourself, and the lower box shows system environment variables that only users with Administrator privileges can modify.

Alternatively, you can gain access to this ‘Environment Variables’ dialog box from the Command Prompt or PowerShell command line with:

#= pwsh/cmd
$> rundll32.exe sysdm.cpl,EditEnvironmentVariables

You can double-click on any variable to modify its value. That will save modifications in the Registry. For this to have effect, only new programs you open, like a new PowerShell session, will see these modifications. That is because programs generally only read variables from the Registry on startup, and makes a copy of it.

ℹ️ NOTEWindows Registry Variables
When a program is launched via the Windows GUI, a copy of the system environment variables is first made, then any changes and additions from the user environment variables are copied. Generally, you only want to modify user environment variables. Modifying the wrong system environment variables can lead to an unworkable system.

Create/Modify Variables

You can create new environment variables that do not yet exist. Again, the method depends on your operating system and shell.

Unix-Like

To set a session-only (non-exported) environment variable (var) to some value, you would use this syntax in a command-line:

     ‹var›=‹value›

There must be no spaces around the equals sign =. If the value contains spaces or shell special characters, enclose the value in single quotes (safer) or double quotes (more flexible):

     ‹var›='‹value›'
     ‹var›="‹value›"

For an environment variable to be ‘visible’ to child processes, it must be exported using the export command. More than one can be exported at the same time.

     export ‹var›
     export ‹var₁› ‹var₂› …

One can create and export at the same time:

     export ‹var›=‹value›
     export ‹var₁›=‹value₁› ‹var₂›=‹value₂› …

Below, we create an environment variable called MYVAR with value My Value. For good measure we expand it to verify its existence and value:

#= sh
$> export MYVAR="My Value" 
$> echo "MYVAR's value is: $MYVAR"
$> echo "MYVAR's value is: ${MYVAR}"

You can also modify existing variables using the same syntax.

PowerShell

To create environment variables in PowerShell, we simply assign to an item in the Env: provider. Spaces around the equal sign is not significant.

     $Env:‹var› = ‹value›

The value part of an environment variable is always a string. If the value contains spaces, or shell special characters, the value must be quoted using single quotes (safer) or double quotes (allows expansions).

     $Env:‹var› = '‹value›'
     $Env:‹var› = "‹value›"

Below, we create an environment variable called MYVAR with value My Value. For good measure, we expand it to verify its existence and value:

#= pwsh
$> $Env:MYVAR = "My Value"
$> echo "MYVAR's value is: $Env:MYVAR"
$> echo "MYVAR's value is: ${Env:MYVAR}"

If the variable MYVAR already exists, the above syntax will give it a new value.

Command Prompt

The Command Prompt's set command can be used to create new environment variables, or assign a new value to and existing variable. If the value contains special characters like spaces, it must be enclosed in double quotes:

     set ‹var›=‹value›
     set ‹var›="‹value›"

There must be no spaces around the equal sign. Below, we create an environment variable called MYVAR with value My Value. For good measure, we expand it to verify its existence and value:

#= cmd
$> set MYVAR="My Value"
$> echo "MYVAR's value is: %MYVAR%"

If the variable MYVAR already exists, the above syntax will give it a new value.

Persistence

Setting and modifying variables on the command-line will not persist. The moment the shell session is closed, all changes are lost. In Unix-like operating systems, variables can be persisted (saved) in text files. On Windows, variables to be persisted, lives in the Registry.

Unix-Like Persistence

This unfortunately, this depends on your operating system, and can even vary across Linux distributions. Administrators of Unix-like systems (root) can also customise the locations where variables are persisted. These files are sourced instead of executed with child shell process.

The basic principle is that system environment variables are saved in files under the /etc directory. If you are lucky, this will be /etc/profile, or /etc/bash_profile. When a user logs in, this file is sourced, followed by a shell-specific file in the user's home directory. Only root or users with sudo privileges can modify files under /etc.

A user's shell profile file(s) are in their home directory, and starts with a period (.), which is why they are often called ‘dotfiles’. The user ‘dotfiles’ can amend or add to the environment variables that was set by loading the system or global environment variables from /etc, which takes place first.

The mechanics for persisting variables are simple: edit the right file with an editor. The problem people face is ‘which file?’. And… there is not easy answer. What is further complicating the matter on Unix-like systems, is that different files are sourced, depending on whether the shell is a login interactive shell, a non-login interactive shell, or a non-interactive shell.

This will take a long time to list all the possibilities. Best to consult and expert in your operating system and shell domain. Here are some common locations for some common shells.

Bash

For interactive login shells, the following files are typical:

For interactive non-login shells, only the following are sourced:

Bash does not load any of these files for non-interactive shells like subshells.

Korn

The ksh shell, loads the following for interactive login shells:

For interactive non-login shells, ksh only loads:

Like bash, ksh does not load any of these files for non-interactive shells like subshells.

Zsh

For login interactive shells, zsh loads the following, in this order:

For interactive non-login shells, the following are loaded in order:

For non-interactive shells, /etc/zsh/zshenv and $HOME/.zshenv are always sourced.

For zsh, we recommend you make changes in $HOME/.zshenv, especially for custom paths (PATH). This file is source for all kinds of shells, interactive or not.

Windows Persistence

Windows store system or global environment variables in the HKLM\Environment (HKEY_LOCAL_MACHINE) key. If you have administrator rights you can use a registry editor to edit these variables. Or, you can look for ‘Edit system environment variables’ in the Start Menu. This will provide you with a GUI where you can inspect, add or edit system environment variables.

Each user's persisted environment variables are stored under HKCU\Environment (HKEY_CURRENT_USER) key. If you search for ‘Edit environment variables for your account’ in the Start Menu, you will be presented with a GUI where you can inspect, add or edit personal environment variables.

We can modify variables stored in the environment, add variables, from either a Command Prompt, or PowerShell, command-line. The commands used are different though. PowerShell has several options, but we show the shortest possible variation below:

#= pwsh
$> sp HKCU/Environment ‹var› ‹value›
#= cmd
$> setx ‹var› ‹value›

Note that setx does not require an equals sign like set does.

PATH Variable

The PATH variable contains a list of directories (paths). This list is separated by a path separator, which is a colon (:) in Unix-like operating systems, and semicolon (;) on Windows.

When you run a command, .e.g., python, your shell will look for the python executable (or python.exe on Windows), in your PATH. If it cannot be found, you can still run python, but you will have to provide a full or relative path to the executable, which is very inconvenient.

If an executable is not ‘on your PATH’, you can modify the PATH environment variable, by adding an additional new-path directory to the existing list. For the Unix-shells, we use export to make the result visible in child processes of the current shell.

#= sh
$> export PATH="‹new-path›:$PATH"
#= pwsh
$> $Env:PATH = "‹new-path›;$Env:PATH"
#= cmd
$> set PATH="‹new-path›;%PATH%"

In the above example, we added new-path in front of all existing paths to ensure that it is searched first. To add it at the end, you can do the following:

#= sh
$> export PATH="$PATH:‹new-path›"
#= pwsh
$> $Env:PATH += ";‹new-path›"
#= cmd
$> set PATH="%PATH%;‹new-path›"

This becomes important and useful when your Python installation's binaries directory is not listed in your PATH, or when you have to deal with multiple Python versions (which is often reality).

Modifying an environment variable like PATH on the command-line, will only last for the current command-line session. If you want it to persist across sessions, or reboots, you will have to put the modification in a profile file (Unix-like systems) or in the Windows Registry.

#= bash 
$> echo "export PATH="‹new-path›:$PATH" >> $HOME/.bash_profile"
#= bash on ubuntu 
$> echo "export PATH="‹new-path›:$PATH" >> $HOME/.profile"
#= zsh 
$> echo "export PATH="‹new-path›:$PATH" >> $HOME/.zshenv"
$= pwsh
$> [System.Environment]::SetEnvironmentVariable(
··    'PATH', "‹new-path›;$Env:PATH", 'User')
$> sp HKCU:\Environment PATH "‹new-path›;$Env:PATH"
$= cmd
$> setx PATH "‹new-path›;%PATH%"
ℹ️ NOTEWindows Registry
Above, sp is an alias for Set-ItemProperty. All the Windows examples will set the PATH in the user's registry (HKCU), not the System registry (HKLM). To set it system-wide, you need to run the commands in a ‘Run as Administrator’ session, and where appropriate, change User to System, and HKCU to HKLM.

You can of course use the Windows environment variable editor GUI to modify the PATH environment variable stored in the Registry. The interface will show one path per line, which you can move up and down with buttons. It also allows you to edit a single path, or add another path.

Searching PATH

You can verify if an executable (command) is reachable via the PATH environment variable; in other words: you can determine if an executable is ‘on your PATH’. It will also show which of duplicate executables will be found. For example, you may have several Python versions installed. The one that is ‘active’, is the first one found as the directories in PATH are scanned.

For Unix-like operating systems, you can use the which command; in PowerShell, you can use Get-Command or its gc alias; in the Command Prompt, you could use the where command

The where command will show all command executables found, in the order they were found. It is the first one, that is important.

ℹ️ NOTEWindows' Fake Python
A stock Windows installation has a ‘fake’ python.exe executable that will be on your PATH. It is located in
C:\Users\‹user›\AppData\Local\Microsoft\WindowsApps.
If this is the first python.exe showing up, running it will take you to the Windows Store, from where you can install Python. We do not recommend this route. Install Python ‘normally’ from python.org, and make sure its python.exe can be found first.

On Windows, you should have 3 Python related paths, in the following order. Here python-install-dir refers to something like C:\Program Files\Python310, (or …Python311) — it all depends on where is was installed on your PC:

A Unix-like OS will have similar directories as determined by the package maintainers, except that the first will by default be $HOME/.local/bin.

When you activate a Python virtual environment, the virtual environment's directories will be added in front of these paths.

Copyright © 2026 Codi Matters