Report this

What is the reason for this report?

How To View and Update the Linux PATH Environment Variable

Updated on May 3, 2026
How To View and Update the Linux PATH Environment Variable

The author selected the Wikimedia Foundation to receive a donation as part of the Write for DOnations program.

Introduction

The Linux PATH environment variable is a colon-separated list of directories the shell searches when you run a command. Each time you enter a command name such as python3, grep, or myapp, the shell checks directories in PATH from left to right and runs the first executable match it finds.

In this tutorial, you will view PATH, change it temporarily and permanently across bash and zsh, verify changes, remove entries, and troubleshoot common failures.

Examples in this guide are validated on Ubuntu 22.04, Debian 12, and Rocky Linux 9. Commands are shown with expected output so you can compare your results and confirm each change is applied as intended.

Key Takeaways

  • PATH is a colon-separated list of directories the shell searches left to right when resolving a command.
  • echo $PATH and printenv PATH both display the current value.
  • export PATH=$PATH:/new/dir changes PATH for the current session only.
  • Permanent changes go in ~/.bashrc for interactive bash shells, ~/.zshrc for zsh, and /etc/environment for system-wide values.
  • which, type -a, and command -v confirm which binary a command resolves to.
  • Either source ~/.bashrc or a new shell session is required to apply changes.
  • Order matters: directories listed earlier in PATH take precedence over later ones.

Prerequisites

Understanding How the Linux PATH Variable Works

What PATH Contains and How the Shell Uses It

PATH stores absolute directory paths separated by colons. When you run a command without a full path, your shell inspects each directory in order and executes the first matching file with execute permissions.

To inspect your PATH as one directory per line, run:

tr ':' '\n' <<< "$PATH"
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/local/games
/usr/games

If the same executable name exists in more than one directory, the first directory in this list wins.

How PATH Is Inherited by Processes and Subshells

Child processes inherit exported environment variables from the parent process. A shell variable exists only in the current shell until you mark it with export.

MYVAR="hello"
bash -c 'echo $MYVAR'   # prints nothing

export MYVAR="hello"
bash -c 'echo $MYVAR'   # prints: hello

PATH follows this same rule.

Step 1 - Viewing the Current PATH Variable

Using echo to Display PATH

echo $PATH is the fastest way to see what directories your shell searches when running a command:

echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games

The output is a single string where each directory is separated by :.

Using printenv to Display PATH

printenv PATH reads directly from the process environment rather than through shell expansion, making it the more reliable option in scripts and non-interactive contexts:

printenv PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games

Because printenv only prints exported variables, it cleanly distinguishes inherited environment from local shell variables.

Reading PATH in a Script Context

Scripts invoked with bash script.sh see a different PATH than your interactive shell because they do not source ~/.bashrc or ~/.bash_profile. This script prints the PATH a non-interactive bash process actually receives:

#!/usr/bin/env bash
echo "Script PATH: $PATH"

To make a script’s PATH reliable regardless of how it is invoked, define PATH explicitly at the top of the script before any 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"

Alternatively, use the full absolute path to each command, for example /usr/bin/python3 instead of python3, so the script does not depend on PATH at all.

Step 2 - Adding a Directory to PATH for the Current Session

Using export to Set a Temporary PATH Change

export marks a variable for inheritance by child processes and updates it immediately in the current shell. To add a directory to PATH for the current session, prepend it for higher priority or append it 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"

Prepending gives the new directory higher priority than system directories, which is useful when installing a newer version of a tool alongside the system version. Appending is safer for general use.

Verifying the Change Took Effect

Two commands confirm the change: echo $PATH shows the raw value, and which shows which binary the shell will actually run:

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 change applies to the current shell session only. When you close the terminal or start a new session, PATH resets to its default value.

Step 3 - Adding a Directory to PATH Permanently

Choosing the Right Configuration File

The correct startup file depends on your shell and whether the session is login or interactive non-login. Choose the file that matches how your shell is launched.

File Scope When Sourced Shells
~/.bashrc Per user Every interactive non-login bash shell bash
~/.bash_profile Per user Login bash shells (typically sources ~/.bashrc) bash
~/.profile Per user Login shells when no ~/.bash_profile exists bash, sh, dash
~/.zshrc Per user Every interactive zsh shell zsh
~/.zprofile Per user Login zsh shells (equivalent to ~/.bash_profile for zsh) zsh
/etc/environment System-wide Read by PAM at login; not a shell script All
/etc/profile System-wide Login shells bash, sh
/etc/profile.d/*.sh System-wide Sourced by /etc/profile bash, sh

For most interactive use on a desktop or server where you are the only user, ~/.bashrc (bash) or ~/.zshrc (zsh) is the correct file.

Editing ~/.bashrc for Bash Users

Appending an export line to ~/.bashrc makes the PATH change available in every new interactive bash session. Open the file:

nano ~/.bashrc

Scroll to the bottom and append:

export PATH="$PATH:/opt/myapp/bin"

Load the change without logging out:

source ~/.bashrc

Verify:

echo $PATH

If /opt/myapp/bin appears in the output, the update is active for new commands in the current terminal.

Editing ~/.zshrc for Zsh Users

For zsh, the equivalent file is ~/.zshrc. Open it:

nano ~/.zshrc

Append the export line:

export PATH="$PATH:/opt/myapp/bin"

Reload configuration:

source ~/.zshrc

Confirm:

echo $PATH

If your system opens login zsh shells and not interactive non-login shells, use ~/.zprofile instead.

Editing /etc/environment for System-Wide Changes

/etc/environment is parsed by PAM at login and is not a shell script, so shell syntax including $PATH variable expansion does not work in it. Read the current value before editing:

grep PATH /etc/environment

Edit the file:

sudo nano /etc/environment

Set the complete literal value, including existing directories and the new one:

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin"

Do not use $PATH inside /etc/environment. Variable expansion is not supported in this file. Always write the complete directory list as a literal string.

Changes in /etc/environment take effect after the next login, not after sourcing in the current shell.

Reloading Your Shell Configuration Without Logging Out

A new export line written to ~/.bashrc is not active until the file is sourced. Three methods 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 starts a new interactive non-login shell, so it sources ~/.bashrc but not ~/.bash_profile. If your export line is in ~/.bash_profile only, use source ~/.bash_profile or open a new login session instead.

Step 4 - Verifying That PATH Changes Are Working

Using which to Check Binary Resolution

which returns the first executable match for a command name across all PATH directories. After a PATH change, run it to confirm the shell resolves the command to the expected binary:

which python3
/usr/bin/python3

The path returned is what the shell will execute next time you run the command, assuming nothing in the bash hash cache or alias table overrides it.

Using type and command -v for Verification

type -a goes further than which. It reports every match across PATH, plus any aliases or shell functions with the same name. Use it when you need to verify that the correct version is first in resolution order:

type -a python3
python3 is /usr/bin/python3
python3 is /usr/local/bin/python3

Run command -v for a POSIX-friendly single-path check:

command -v python3
/usr/bin/python3

type is a shell builtin that reports aliases, functions, and all PATH matches, while which only checks PATH directories and returns the first match. Use type -a when you need to see every candidate to diagnose version conflicts.

Opening a New Shell Session to Confirm Persistence

Running echo $PATH in the same session that applied export does not confirm persistence. It only confirms the current session state. Start a fresh shell process to verify the value comes from the startup file:

exec bash
echo $PATH

If the new directory appears in the output, the startup file is correctly configured. If not, the export line is missing, in the wrong file, or sitting below an early-return guard.

Step 5 - Removing or Deduplicating Entries from PATH

Manually Removing a Specific Directory

To remove /opt/myapp/bin from the current session:

PATH=$(echo "$PATH" | sed -e 's|/opt/myapp/bin:||g' -e 's|:/opt/myapp/bin||g')
export PATH

The trailing-colon pattern removes the directory when it is followed by a colon, covering start and middle positions. The leading-colon pattern removes it when it is preceded by a colon, covering middle and end positions. Running both together covers all positions. Run echo $PATH afterward to confirm removal.

Preventing Duplicate Entries When Sourcing Config Files

Sourcing ~/.bashrc multiple times in a session, for example after editing it, can append the same directory each time. Use this guard pattern to add the path only once:

case ":$PATH:" in
  *":/opt/myapp/bin:"*) ;;
  *) export PATH="$PATH:/opt/myapp/bin" ;;
esac

Wrapping colons around both $PATH and the target directory makes the pattern match a full entry, not a substring of a longer path.

Troubleshooting Common PATH Problems

PATH Change Not Persisting After Logout

The export command updates PATH in the current shell process only. When that process exits, the change is gone. To confirm this is what happened, open a new terminal and run:

echo $PATH

If the directory you added is absent, the change was never written to a startup file. To trace exactly which files bash sources at login and in what order, run:

bash -lxv 2>&1 | head -50

The -l flag forces a login shell, -x enables trace output, and -v prints each line as it is read. Look for lines sourcing ~/.profile, ~/.bash_profile, or /etc/profile to confirm which file controls your login PATH. Then append your export line to the correct file and source it:

echo 'export PATH="$PATH:/opt/myapp/bin"' >> ~/.bashrc
source ~/.bashrc

Command Not Found After Adding to PATH

Cause: PATH was updated in a subshell or script that exited, the wrong startup file was edited, or the current session has not yet loaded the change. Diagnostic:

echo $PATH
grep -n PATH ~/.bashrc ~/.profile ~/.bash_profile 2>/dev/null

Confirm that the export line is present in the correct file and that source has been run or a new session has been opened.

Wrong Version of a Binary Being Resolved

Cause: a directory containing an older version of the binary appears earlier in PATH than the directory containing the newer version. Diagnostic:

type -a python3

Fix: prepend the directory containing the desired version using export PATH="/opt/myapp/bin:$PATH", or remove the directory containing the unwanted version using the sed pattern from Step 5.

PATH Changes Not Applying to GUI Applications

Cause: most desktop environments source ~/.profile and /etc/environment at login, not ~/.bashrc. A change in ~/.bashrc only affects terminal emulators that spawn interactive non-login shells. Fix: move the export line to ~/.profile, or add the directory to /etc/environment, then log out and back in.

Managing PATH in Non-Standard Environments

PATH in Shell Scripts and Cron Jobs

Cron runs with a minimal default PATH (typically /usr/bin:/bin). Commands available in your interactive shell may not be found. Set PATH at the top of the crontab file, before any job definitions. Open the crontab with crontab -e and add the PATH assignment first:

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 line applies to every job defined below it in the same crontab file. If a script called by cron also relies on PATH-dependent commands, add the same PATH assignment at the top of that script.

PATH in Docker Containers and Dockerfiles

Use the ENV instruction in a Dockerfile to extend PATH for the image:

ENV PATH="/opt/myapp/bin:${PATH}"

ENV persists across all subsequent layers and into the running container, so every RUN, CMD, and ENTRYPOINT instruction sees the updated value.

Using direnv for Project-Scoped PATH Management

direnv loads and unloads environment variables automatically when you enter or leave a directory. Install it and add the shell hook to your startup file:

sudo apt install direnv
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
source ~/.bashrc

On Rocky Linux, Fedora, or RHEL, replace the install line with sudo dnf install direnv. For zsh users on either distribution, replace bash with zsh in the hook command. The hook is required. Without it, direnv will not activate on directory change.

Create a .envrc file in your project root:

PATH_add ./bin

Allow it once:

direnv allow

PATH reverts to its previous value when you cd out of the project.

Common PATH Gotchas in Production

The following scenarios are the most common reasons a correctly configured PATH still does not work as expected in real deployments.

sudo Ignores Your PATH

Running a command with sudo often fails with “command not found” even when the command works without sudo. The cause is secure_path in /etc/sudoers, which replaces PATH entirely when sudo is invoked.

Check the current 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 not listed, sudo myapp will fail regardless of your user PATH. To fix this without disabling secure_path, use the full path:

sudo /opt/myapp/bin/myapp

Or add the directory to secure_path by editing /etc/sudoers with visudo:

sudo visudo

Change the secure_path line to include your directory:

Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin"

Always use visudo to edit /etc/sudoers. Editing the file directly with a text editor and introducing a syntax error will lock you out of sudo on that system.

SSH Non-Interactive Shells Do Not Source ~/.bashrc

Running a command over SSH with ssh user@host 'mycommand' spawns a non-interactive, non-login shell. This shell sources neither ~/.bashrc nor ~/.bash_profile, so PATH changes in those files are invisible to it.

To verify what PATH an SSH non-interactive shell sees:

ssh user@host 'echo $PATH'
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin

The output is a minimal system PATH set by sshd, with none of the directories from your interactive shell’s startup files. To make PATH available in this context, set it in ~/.bashrc and guard the block so it runs even in non-interactive shells:

export PATH="$PATH:/opt/myapp/bin"

Check whether a [ -z "$PS1" ] && return guard exists near the top of your ~/.bashrc. This line causes bash to exit early for non-interactive shells, skipping everything below it. If the guard is present, move the export PATH line above it. If the guard is absent, the export line can stay at the bottom of the file. Alternatively, define PATH in ~/.profile and ensure ~/.bashrc sources it.

Bash Caches Binary Locations

After updating PATH, bash may still run the old binary because it caches the location of previously executed commands in a hash table. The cached entry overrides PATH lookup for that command name.

Clear the cache after a PATH change:

hash -r

To check whether a specific command is cached and where it points:

hash python3
hits    command
   3    /usr/bin/python3

If the cached path is stale, hash -r clears all entries and forces a fresh PATH lookup on the next invocation.

Command Resolution Precedence

PATH is not the first place bash looks when you run a command. The resolution order is:

  1. Aliases (defined with alias)
  2. Shell functions
  3. Shell builtins (cd, echo, type, etc.)
  4. Hashed locations (the binary cache described above)
  5. PATH directory scan

This is why type -a is more useful than which for diagnosing unexpected behavior. If type python3 returns python3 is aliased to python, the alias takes precedence over any PATH entry. Remove or rename the alias to reach the binary.

macOS PATH Composition Differs from Linux

On macOS, the system runs /usr/libexec/path_helper at login to assemble PATH from two sources: /etc/paths (one directory per line) and files inside /etc/paths.d/. This runs before shell startup files, so directories listed there appear in PATH before anything in ~/.zshrc or ~/.bash_profile.

To add a directory system-wide on macOS, create a file in /etc/paths.d/:

sudo sh -c 'echo /opt/myapp/bin > /etc/paths.d/myapp'

The file takes effect on the next login. To verify:

cat /etc/paths
ls /etc/paths.d/

This section applies to macOS only. On Linux systems covered in this tutorial, /etc/paths and path_helper do not exist.

PATH in systemd Service Units

When running applications as systemd services, the PATH from your user environment is not inherited. systemd starts services with a minimal environment. Commands installed in /opt/myapp/bin or similar locations will not be found unless PATH is set explicitly in the unit file.

Set PATH in the [Service] block 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

For multiple environment variables, use an EnvironmentFile:

[Service]
EnvironmentFile=/etc/myapp/environment
ExecStart=/opt/myapp/bin/myapp

Where /etc/myapp/environment contains:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin
MYAPP_ENV=production

After editing the unit file, reload the daemon and restart the service:

sudo systemctl daemon-reload
sudo systemctl restart myapp

Frequently Asked Questions

What Is the Linux PATH Environment Variable?

PATH is a colon-separated list of directory paths that the shell searches, from left to right, when you type a command. When you run python3, the shell checks each directory in PATH until it finds an executable named python3, then runs it. Without PATH, every command would require typing its full absolute path.

How Do I View My Current PATH in Linux?

Run echo $PATH or printenv PATH in any terminal to display the current value. Both commands print the same colon-separated list of directories. To view one directory per line, run tr ':' '\n' <<< "$PATH".

What Is the Difference Between a Temporary and Permanent PATH Change in Linux?

Running export PATH="$PATH:/new/dir" in the terminal applies the change to the current shell session only. When the session ends, PATH returns to the value set by the startup files. To persist the change, write the export line to ~/.bashrc (bash) or ~/.zshrc (zsh) and source the file.

Which File Should I Edit to Permanently Add a Directory to PATH in Linux?

Edit ~/.bashrc for interactive bash sessions on a server or desktop where you log in as a single user. Use ~/.profile or ~/.bash_profile for login shell sessions, and /etc/environment when the change must apply to all users on the system. The table in Step 3 lists the scope and sourcing behavior of each file.

Why Is My PATH Not Updating After I Run export in the Terminal?

export in a script does not affect the parent shell because the script runs in a subshell. Changes must be sourced (. script.sh or source script.sh) to apply to the current shell, or written to a startup file and loaded in a new session. Run echo $PATH immediately after export to confirm the change is visible in the current session.

How Do I Add a Directory to PATH in zsh?

Open ~/.zshrc in a text editor, add export PATH="$PATH:/opt/myapp/bin" at the bottom, save the file, and run source ~/.zshrc. For login zsh shells, use ~/.zprofile instead of ~/.zshrc.

How Do I Check Which Binary a Command Is Resolving To After Updating PATH?

Run which python3 to see the first match in PATH. Run type -a python3 to list every match across all PATH directories, which is useful when multiple versions are installed. Run command -v python3 for a POSIX-portable alternative to which.

How Do I Remove a Directory from PATH in Linux?

Run the following to remove /opt/myapp/bin from the current session:

PATH=$(echo "$PATH" | sed -e 's|/opt/myapp/bin:||g' -e 's|:/opt/myapp/bin||g')
export PATH

To make the removal permanent, delete or comment out the export line that added the directory from ~/.bashrc, ~/.zshrc, or whichever startup file contains it, then source the file.

Conclusion

This tutorial walked through the full lifecycle of PATH management on Linux: reading the current value, making temporary and permanent changes across bash and zsh, choosing the right startup file for your session type, verifying that the correct binary is resolved, removing and deduplicating entries, and diagnosing the failures that occur in production environments including sudo stripping PATH, SSH non-interactive shells, stale binary caches, and systemd service isolation.

You can now configure PATH for any user-installed tool, select the right startup file for your shell and login mode, and diagnose why a command is not found or resolves to the wrong binary.

Next, continue with How To Read and Set Environmental and Shell Variables on Linux, An Introduction to the Linux Terminal, and An Introduction to Useful Bash Aliases and Functions.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Caitlin Postal
Caitlin Postal
Editor
Technical Editor
See author profile
Vinayak Baranwal
Vinayak Baranwal
Editor
Technical Writer II
See author profile

Building future-ready infrastructure with Linux, Cloud, and DevOps. Full Stack Developer & System Administrator. Technical Writer @ DigitalOcean | GitHub Contributor | Passionate about Docker, PostgreSQL, and Open Source | Exploring NLP & AI-TensorFlow | Nailed over 50+ deployments across production environments.

Category:

Still looking for an answer?

Was this helpful?


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Start building today

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

Dark mode is coming soon.