How the Linux PATH Environment Variable Works and How to Update It
The Linux PATH environment variable contains a colon-separated sequence of directories that the shell searches whenever you execute a command. When you enter a command such as python3, grep, or myapp, the shell searches the directories stored in PATH from left to right and executes the first matching file that has permission to run.
This tutorial explains how to inspect PATH, modify it temporarily or permanently in bash and zsh, confirm that updates are working, remove directory entries, and diagnose common problems.
The examples have been validated on Ubuntu 22.04, Debian 12, and Rocky Linux 9. Commands include expected output where appropriate so you can compare the results and verify that each modification has been applied correctly.
Key Takeaways
PATHcontains directories separated by colons, and the shell searches them from left to right when locating a command.echo $PATHandprintenv PATHcan both be used to display the current value.export PATH=$PATH:/new/dirmodifiesPATHonly for the active shell session.- Persistent changes can be placed in
~/.bashrcfor interactive bash shells,~/.zshrcfor zsh, or/etc/environmentfor system-wide configuration. which,type -a, andcommand -vhelp identify the executable to which a command resolves.- After editing a shell configuration file, use
source ~/.bashrcor start another shell session to activate the update. - Directory order is important because entries appearing earlier in
PATHhave priority over entries appearing later.
Prerequisites
- A Linux system using bash or zsh. The commands have been validated on Ubuntu 22.04, Debian 12, and Rocky Linux 9.
- A non-root account with sudo privileges.
- Basic familiarity with Linux environment variables and shell variables.
Understanding How the Linux PATH Variable Works
What PATH Contains and How the Shell Uses It
PATH consists of absolute directory paths separated with colons. If you execute a command without specifying its complete path, the shell examines these directories one at a time and runs the first matching executable file it encounters.
To display the directories from your PATH one entry per line, run:
tr ':' '\n' <<< "$PATH"
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/local/games
/usr/games
If executables with the same filename are present in multiple directories, the executable located in the directory appearing first in this list takes priority.
How PATH Is Inherited by Processes and Subshells
Child processes receive exported environment variables from their parent process. A regular shell variable remains available only inside the current shell until it is exported.
MYVAR="hello"
bash -c 'echo $MYVAR' # prints nothing
export MYVAR="hello"
bash -c 'echo $MYVAR' # prints: hello
The PATH variable follows the same inheritance behavior.
Step 1 – Viewing the Current PATH Variable
Using echo to Display PATH
The quickest way to inspect the directories searched by your shell is to run echo $PATH:
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
The command returns a single string in which each directory is separated from the next one by a : character.
Using printenv to Display PATH
printenv PATH retrieves the value directly from the process environment instead of relying on shell variable expansion. This makes it especially useful in scripts and other non-interactive situations:
printenv PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
Because printenv displays exported variables only, it provides a clear way to distinguish values inherited through the environment from variables that exist only in the current shell.
Reading PATH in a Script Context
A script launched with bash script.sh can receive a different PATH from the one available in your interactive shell because this type of process does not normally load ~/.bashrc or ~/.bash_profile. The following script displays the PATH inherited by a non-interactive bash process:
#!/usr/bin/env bash
echo "Script PATH: $PATH"
If a script must use a predictable PATH regardless of the environment from which it starts, assign the variable explicitly near the beginning of the script before executing commands that depend on it:
#!/usr/bin/env bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo "Script PATH: $PATH"
Another option is to call every program with its full absolute location, such as /usr/bin/python3 instead of python3. Doing so removes the script’s dependency on PATH.
Step 2 – Adding a Directory to PATH for the Current Session
Using export to Set a Temporary PATH Change
The export command updates the variable in the active shell and makes it available to child processes. To add another directory to PATH for the current session, place it at the beginning for higher priority or at the end for lower priority:
# Prepend: /opt/myapp/bin is checked before all existing directories
export PATH="/opt/myapp/bin:$PATH"
# Append: /opt/myapp/bin is checked after all existing directories
export PATH="$PATH:/opt/myapp/bin"
Placing the directory first gives it priority over system directories. This is useful when a newer version of a program is installed alongside the system-provided version. Adding the directory at the end is generally the safer choice for normal use.
Verifying the Change Took Effect
You can confirm the update with two commands. echo $PATH displays the complete variable, while which shows the executable that will be selected for a particular command:
echo $PATH
which myapp
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/opt/myapp/bin
/opt/myapp/bin/myapp
This modification exists only in the current shell session. Closing the terminal or beginning another session causes PATH to return to the value defined by the relevant startup configuration.
Step 3 – Adding a Directory to PATH Permanently
Choosing the Right Configuration File
The startup file you should modify depends on the shell being used and whether the session is a login shell or an interactive non-login shell. Select the configuration file that corresponds to the way your shell is started.
| File | Scope | When Sourced | Shells |
|---|---|---|---|
~/.bashrc |
Per user | Every interactive non-login bash shell | bash |
~/.bash_profile |
Per user | Login bash shells, which commonly source ~/.bashrc |
bash |
~/.profile |
Per user | Login shells when ~/.bash_profile does not exist |
bash, sh, dash |
~/.zshrc |
Per user | Every interactive zsh shell | zsh |
~/.zprofile |
Per user | Login zsh shells and serves a role similar to ~/.bash_profile |
zsh |
/etc/environment |
System-wide | Read by PAM during login and is not executed as a shell script | All |
/etc/profile |
System-wide | Login shells | bash, sh |
/etc/profile.d/*.sh |
System-wide | Loaded by /etc/profile |
bash, sh |
For typical interactive use on a desktop or server with a single account, ~/.bashrc is normally appropriate for bash and ~/.zshrc for zsh.
Editing ~/.bashrc for Bash Users
Adding an export command to ~/.bashrc makes the updated PATH available whenever a new interactive bash session starts. Open the file:
nano ~/.bashrc
Move to the end of the file and add:
export PATH="$PATH:/opt/myapp/bin"
Apply the updated configuration without signing out:
source ~/.bashrc
Then verify the result:
echo $PATH
If /opt/myapp/bin is included in the displayed value, the new configuration is active for commands executed in the current terminal.
Editing ~/.zshrc for Zsh Users
For zsh, the corresponding configuration file is ~/.zshrc. Open it with:
nano ~/.zshrc
Add the export command:
export PATH="$PATH:/opt/myapp/bin"
Reload the configuration:
source ~/.zshrc
Confirm the current value:
echo $PATH
If the system creates login zsh shells rather than interactive non-login shells, place the setting in ~/.zprofile instead.
Editing /etc/environment for System-Wide Changes
The /etc/environment file is processed by PAM during login and is not interpreted as a shell script. As a result, shell expressions such as $PATH expansion are not supported. Before making changes, inspect the existing value:
grep PATH /etc/environment
Open the configuration file:
sudo nano /etc/environment
Specify the entire value literally, including the existing directories and the additional directory:
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin"
Do not place $PATH in /etc/environment. Because this file does not support variable expansion, the complete directory sequence must be written as a literal string.
Updates made in /etc/environment become active after the next login rather than by sourcing the file in the current shell.
Reloading Your Shell Configuration Without Logging Out
An export command added to ~/.bashrc does not affect the current shell until the configuration file is loaded. The following three approaches can reload the configuration without requiring a logout:
# Source the file directly
source ~/.bashrc
# Equivalent shorthand
. ~/.bashrc
# Replace the current shell process (sources ~/.bashrc but not ~/.bash_profile)
exec bash
exec bash launches another interactive non-login bash shell, so ~/.bashrc is loaded while ~/.bash_profile is not. If the export command exists only in ~/.bash_profile, use source ~/.bash_profile or begin a new login session.
Step 4 – Verifying That PATH Changes Are Working
Using which to Check Binary Resolution
which searches the directories in PATH and reports the first executable matching the specified command name. After modifying PATH, use it to check that the desired executable is being selected:
which python3
/usr/bin/python3
The returned path identifies the binary that will normally run the next time the command is entered, provided that an alias or a cached bash command location does not override the lookup.
Using type and command -v for Verification
type -a provides more information than which. It displays every matching command found through PATH and also identifies aliases and shell functions with the same name. This is useful when checking which installed version has the highest resolution priority:
type -a python3
python3 is /usr/bin/python3
python3 is /usr/local/bin/python3
For a POSIX-friendly command that returns a single resolution result, use:
command -v python3
/usr/bin/python3
type is implemented as a shell builtin and can identify aliases, functions, and every matching PATH entry. By comparison, which searches PATH directories and normally reports the first result. Use type -a when investigating conflicts between multiple command versions.
Opening a New Shell Session to Confirm Persistence
Executing echo $PATH immediately after an export command proves only that the current process contains the new value. It does not show that the setting will survive another session. Start a fresh shell and inspect PATH again:
exec bash
echo $PATH
If the newly added directory remains visible, the startup configuration is working. If it disappears, the export command may be absent, stored in the wrong configuration file, or positioned below a startup-file condition that exits early.
Step 5 – Removing or Deduplicating Entries from PATH
Manually Removing a Specific Directory
To remove /opt/myapp/bin from the active session, run:
PATH=$(echo "$PATH" | sed -e 's|/opt/myapp/bin:||g' -e 's|:/opt/myapp/bin||g')
export PATH
The pattern containing a trailing colon removes the directory when a colon follows it, which handles entries at the beginning and in the middle. The pattern containing a leading colon removes the directory when a colon precedes it, covering entries in the middle or at the end. Together, the two expressions handle every possible position. Run echo $PATH afterward to verify that the directory has been removed.
Preventing Duplicate Entries When Sourcing Config Files
If you source ~/.bashrc repeatedly during a session, such as after making several edits, a simple append command can insert the same directory more than once. The following guard adds the directory only when it is not already present:
case ":$PATH:" in
*":/opt/myapp/bin:"*) ;;
*) export PATH="$PATH:/opt/myapp/bin" ;;
esac
Adding colons around both $PATH and the directory being tested ensures that the pattern matches an entire directory entry rather than a matching substring inside a longer path.
Troubleshooting Common PATH Problems
PATH Change Not Persisting After Logout
An export command changes PATH only inside the shell process in which it is executed. Once that process terminates, the temporary setting disappears. To check whether this happened, open another terminal and run:
echo $PATH
If the added directory is missing, the modification was not saved in a startup configuration file. To inspect which files bash processes during login and the sequence in which they are loaded, run:
bash -lxv 2>&1 | head -50
The -l option starts a login shell, -x enables execution tracing, and -v prints input lines as bash reads them. Check the output for references to ~/.profile, ~/.bash_profile, or /etc/profile to identify which file influences the login PATH. Then place the export command in the appropriate file and load it:
echo 'export PATH="$PATH:/opt/myapp/bin"' >> ~/.bashrc
source ~/.bashrc
Command Not Found After Adding to PATH
Cause: the PATH modification may have occurred inside a script or subshell that has already exited, the incorrect startup configuration may have been edited, or the current shell may not have loaded the new setting yet.
Diagnostic:
echo $PATH
grep -n PATH ~/.bashrc ~/.profile ~/.bash_profile 2>/dev/null
Verify that the export command appears in the configuration file appropriate for the session and that the file has been sourced or a fresh session has been started.
Wrong Version of a Binary Being Resolved
Cause: a directory containing an older executable may appear before the directory containing the preferred version in PATH.
Diagnostic:
type -a python3
Fix: place the directory containing the desired executable at the beginning with export PATH="/opt/myapp/bin:$PATH", or remove the directory containing the unwanted version by using the sed method from Step 5.
PATH Changes Not Applying to GUI Applications
Cause: many desktop environments process ~/.profile and /etc/environment during login instead of loading ~/.bashrc. A setting added only to ~/.bashrc generally affects terminal applications that create interactive non-login bash sessions.
Fix: place the export command in ~/.profile, or include the directory in /etc/environment, and then sign out and sign back in.
Managing PATH in Non-Standard Environments
PATH in Shell Scripts and Cron Jobs
Cron normally operates with a limited default PATH, commonly /usr/bin:/bin. As a result, programs available from your interactive terminal might not be located by cron. Define PATH near the beginning of the crontab, before the job entries. Open the file using crontab -e and place the assignment before the scheduled commands:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Run myapp every hour
0 * * * * /opt/myapp/bin/myapp >> /var/log/myapp.log 2>&1
The PATH assignment applies to all cron jobs appearing below it in the same crontab. If a script launched by cron also executes commands by name, define the same PATH near the top of that script.
PATH in Docker Containers and Dockerfiles
Inside a Dockerfile, the ENV instruction can be used to extend PATH for the image:
ENV PATH="/opt/myapp/bin:${PATH}"
An ENV setting remains available to later image layers and inside containers created from that image. Therefore, subsequent RUN, CMD, and ENTRYPOINT instructions use the updated value.
Using direnv for Project-Scoped PATH Management
direnv can automatically activate and remove environment settings as you enter and leave directories. Install it and configure the appropriate shell hook in your startup file:
sudo apt install direnv
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
source ~/.bashrc
On Rocky Linux, Fedora, or RHEL, use sudo dnf install direnv instead of the installation command above. If you use zsh on either type of distribution, replace bash with zsh in the hook command. The hook is required because direnv cannot react to directory changes without it.
Create a .envrc file in the root directory of the project:
PATH_add ./bin
Authorize the file once:
direnv allow
After you use cd to leave the project directory, PATH automatically returns to its previous state.
Common PATH Gotchas in Production
The following situations are frequent causes of unexpected command-resolution behavior even when PATH itself appears to be configured correctly in a deployed environment.
sudo Ignores Your PATH
A command can work normally and still return “command not found” when executed with sudo. One common reason is the secure_path option in /etc/sudoers, which can replace the user’s PATH when sudo starts a command.
Inspect the configured secure_path value:
sudo grep secure_path /etc/sudoers
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
If /opt/myapp/bin is missing from this value, sudo myapp can fail even though the directory is present in your normal user PATH. One way to avoid disabling secure_path is to call the command with its complete location:
sudo /opt/myapp/bin/myapp
You can also include the directory in secure_path by opening /etc/sudoers with visudo:
sudo visudo
Modify the secure_path entry so the required directory is included:
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin"
Always modify /etc/sudoers through visudo. Editing it directly with a general text editor can introduce an invalid configuration and prevent sudo from working on the system.
SSH Non-Interactive Shells Do Not Source ~/.bashrc
Executing a remote command with ssh user@host 'mycommand' creates a non-interactive, non-login shell. In this situation, shell startup behavior differs from a normal interactive terminal, and PATH values configured for interactive sessions may not be available.
To inspect the PATH visible to an SSH non-interactive command, run:
ssh user@host 'echo $PATH'
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
The displayed value can be a minimal system PATH supplied by sshd rather than the value seen in your usual interactive shell. To make the required directory available in this situation, define the value where the relevant non-interactive shell can read it:
export PATH="$PATH:/opt/myapp/bin"
Check whether your ~/.bashrc contains a [ -z "$PS1" ] && return condition near the beginning. Such a condition stops further processing when bash is non-interactive, so commands below it will be skipped. If it exists, place the export PATH line above the guard. If the guard is not present, the export command may remain near the end of the file. Another approach is to define PATH in ~/.profile and ensure that the required startup configuration loads it.
Bash Caches Binary Locations
After PATH has been changed, bash may continue executing an older binary because previously located executables can be stored in the shell’s command hash table. A cached location can affect subsequent resolution of that command.
Clear the command-location cache after changing PATH:
hash -r
To determine whether a particular command is present in the cache and identify its stored location, run:
hash python3
hits command
3 /usr/bin/python3
If the saved location is no longer correct, hash -r removes all cached command entries so bash performs another PATH lookup the next time the command is executed.
Command Resolution Precedence
Bash does not always begin with a PATH directory search when resolving a command. The lookup order is:
- Aliases created with
alias - Shell functions
- Shell builtins such as
cd,echo, andtype - Hashed executable locations from the command cache
- The directories listed in
PATH
This resolution sequence explains why type -a is often more informative than which when investigating unexpected command behavior. For example, if type python3 reports that python3 is an alias for python, the alias takes priority over executable files available through PATH. Remove or rename that alias if the binary should be executed instead.
macOS PATH Composition Differs from Linux
On macOS, /usr/libexec/path_helper is used during login to construct PATH using /etc/paths, which stores one directory per line, and files located in /etc/paths.d/. This occurs before normal shell startup files are processed, so directories from those locations can be inserted before entries configured through ~/.zshrc or ~/.bash_profile.
To define another directory system-wide on macOS, create a file inside /etc/paths.d/:
sudo sh -c 'echo /opt/myapp/bin > /etc/paths.d/myapp'
The new entry becomes available after the next login. Verify the configuration with:
cat /etc/paths
ls /etc/paths.d/
This behavior is specific to macOS. The Linux systems discussed in this tutorial do not provide /etc/paths or path_helper.
PATH in systemd Service Units
Applications started as systemd services do not automatically receive the PATH from your interactive user environment. Services start with a limited environment, so executables located in directories such as /opt/myapp/bin may not be found unless the service configuration explicitly defines PATH.
Add PATH to the [Service] section of the unit file:
[Service]
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin"
ExecStart=/opt/myapp/bin/myapp
If several environment variables are required, an EnvironmentFile can be used:
[Service]
EnvironmentFile=/etc/myapp/environment
ExecStart=/opt/myapp/bin/myapp
The corresponding /etc/myapp/environment file can contain:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin
MYAPP_ENV=production
After modifying the unit configuration, reload systemd and restart the application:
sudo systemctl daemon-reload
sudo systemctl restart myapp
Frequently Asked Questions
What Is the Linux PATH Environment Variable?
PATH is a list of directories separated by colons that the shell searches from left to right whenever you enter a command. For example, when you execute python3, the shell examines each directory in PATH until an executable named python3 is found, and then that file is executed. Without PATH, you would generally need to provide the complete absolute location for every command.
How Do I View My Current PATH in Linux?
Run echo $PATH or printenv PATH in a terminal to display the active value. Both return a colon-separated directory list. If you prefer to display one directory on each line, use tr ':' '\n' <<< "$PATH".
What Is the Difference Between a Temporary and Permanent PATH Change in Linux?
Running export PATH="$PATH:/new/dir" directly in a terminal modifies PATH only for the existing shell session. When that session ends, the value is rebuilt from its normal startup configuration. To make the directory persistent, place the export command in ~/.bashrc for bash or ~/.zshrc for zsh and load the configuration.
Which File Should I Edit to Permanently Add a Directory to PATH in Linux?
Use ~/.bashrc for interactive bash sessions on a desktop or server where the setting belongs to one user. For login sessions, use ~/.profile or ~/.bash_profile. If the directory must be included for every user, configure /etc/environment. The table in Step 3 describes the scope and startup behavior of the available files.
Why Is My PATH Not Updating After I Run export in the Terminal?
An export executed inside a normal script cannot update the shell that launched that script because the script runs in another process. To affect the current shell, source the script with . script.sh or source script.sh, or store the change in a startup file and begin another session. Running echo $PATH immediately after an interactive export verifies whether the active shell contains the updated value.
How Do I Add a Directory to PATH in zsh?
Open ~/.zshrc with a text editor, add export PATH="$PATH:/opt/myapp/bin" near the end, save the file, and execute source ~/.zshrc. If you are configuring a login zsh shell, use ~/.zprofile instead.
How Do I Check Which Binary a Command Is Resolving To After Updating PATH?
Use which python3 to display the first executable found through PATH. Use type -a python3 when you want to see every matching command location, which is helpful when multiple versions are installed. For a POSIX-compatible alternative to which, use command -v python3.
How Do I Remove a Directory from PATH in Linux?
To remove /opt/myapp/bin from the active shell session, run:
PATH=$(echo "$PATH" | sed -e 's|/opt/myapp/bin:||g' -e 's|:/opt/myapp/bin||g')
export PATH
To remove it permanently, delete or comment out the export command that originally added the directory in ~/.bashrc, ~/.zshrc, or the relevant startup file, and then load that file again.
Conclusion
This tutorial covered the complete process of managing PATH on Linux, including inspecting its current value, applying temporary and permanent changes in bash and zsh, selecting the appropriate startup file for different session types, checking which executable is resolved, removing or preventing duplicate entries, and troubleshooting problems that can appear in deployed environments. These include sudo using a separate PATH, SSH non-interactive shell behavior, outdated command-location caches, and the isolated environment used by systemd services.
You can now configure PATH for user-installed applications, choose the appropriate startup configuration for your shell and login mode, and determine why a command cannot be found or why it resolves to an unexpected executable.


