The Linux PATH is an environment variable that contains a list of directories the shell searches whenever you type a command. When you type firefox or ls, the shell looks through each directory in your PATH — such as /usr/bin, /usr/local/bin, and /bin — until it finds a matching executable file. Programs are installed into these standard directories so the shell can find them without you needing to type their full location every time.
Introduction: The Mystery of Typeable Commands
You open a terminal on your Linux system and type firefox. Firefox launches. You type git status. Git reports the status of your repository. You type python3 script.py. Python runs your script. But stop and think: how did the shell know where to find these programs? You typed a short name — firefox, git, python3 — without specifying where on the filesystem those programs live. The shell did not ask you for a path. It simply found the programs and ran them.
This works because of one of the most fundamental mechanisms in Unix and Linux: the PATH environment variable. PATH is a list of directories that the shell consults every time you type a command. When you type firefox, the shell does not search your entire filesystem — it looks specifically inside the directories listed in PATH, in order, until it finds an executable named firefox. When it finds one, it runs it.
Understanding PATH transforms several aspects of Linux from mysterious to clear. You will understand why certain commands work in one terminal session but not another. You will know how to make a script you have written runnable from anywhere on your system. You will understand why installing software in non-standard locations sometimes makes it “invisible” to the shell. You will be able to diagnose “command not found” errors quickly and correctly. And you will understand the structure that keeps Linux’s vast collection of programs organized and accessible.
This article takes you from the basics of what PATH is and how it works, through the standard locations where Linux programs live, to practical techniques for viewing and modifying PATH for your own needs.
What Is an Environment Variable?
Before diving into PATH specifically, understanding environment variables in general provides essential context.
The Shell’s Environment
Every shell session — every terminal window you open — has an environment: a collection of named variables that store configuration information used by the shell and by programs launched from it. These environment variables are inherited by child processes, meaning when you run a program from the terminal, that program automatically receives copies of all the environment variables active in your shell session.
Environment variables configure all sorts of behaviors: which editor opens when a program needs you to edit text ($EDITOR), what language and locale to use for output ($LANG), where your home directory is ($HOME), what type of terminal you are using ($TERM), and many more. PATH is simply one of these environment variables — but a particularly important one because it controls how the shell finds commands.
Viewing Environment Variables
To see all currently set environment variables:
$ envThis prints a long list. To view a specific variable, use echo with the variable name preceded by $:
$ echo $HOME
/home/sarah
$ echo $USER
sarah
$ echo $SHELL
/bin/bashThe $ before the variable name tells the shell to substitute the variable’s value rather than using the literal string. echo HOME prints the word “HOME”; echo $HOME prints the path stored in the HOME variable.
The PATH Variable: What It Is and How It Works
PATH’s Structure
PATH contains a colon-separated list of directory paths. View your current PATH:
$ echo $PATH
/home/sarah/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/binEach directory in this list is a place the shell searches for executable programs. The directories are separated by colons (:), and they are searched in order from left to right.
Formatted for readability, this PATH contains:
/home/sarah/.local/bin/usr/local/sbin/usr/local/bin/usr/sbin/usr/bin/sbin/bin/snap/bin
When you type a command, the shell checks directory 1, then directory 2, then directory 3, and so on until it finds an executable with the matching name. The first match wins — if an executable named python3 exists in both /usr/local/bin and /usr/bin, the one in /usr/local/bin is used because it comes earlier in PATH.
The Command Search Process
When you type git and press Enter, the shell performs these steps:
- Check if
gitis a shell built-in command (likecd,echo,pwd). Built-ins are part of the shell itself and do not need to be found in PATH. - Check if
gitmatches an alias or shell function defined in your current session. - Search each directory in PATH, in order:
- Does
/home/sarah/.local/bin/gitexist and is it executable? No. - Does
/usr/local/sbin/gitexist and is it executable? No. - Does
/usr/local/bin/gitexist and is it executable? No. - Does
/usr/sbin/gitexist and is it executable? No. - Does
/usr/bin/gitexist and is it executable? Yes.
- Does
- Run
/usr/bin/gitwith any arguments you provided.
If the shell searches all PATH directories and finds no matching executable, it prints:
bash: git: command not foundThis error is not mysterious — it means the shell exhausted all directories in PATH without finding an executable named git. The program is either not installed, or it is installed in a directory not listed in PATH.
The which and type Commands
Two commands help you understand how the shell resolves command names:
which shows the full path of the executable that would be run:
$ which python3
/usr/bin/python3
$ which git
/usr/bin/git
$ which firefox
/usr/bin/firefoxtype provides more complete information — it tells you whether the command is an alias, a shell function, a built-in, or a program found in PATH:
$ type ls
ls is aliased to 'ls --color=auto'
$ type cd
cd is a shell builtin
$ type python3
python3 is /usr/bin/python3
$ type git
git is /usr/bin/gittype is more informative than which because it reveals the entire resolution — if you have an alias that shadows a program, type shows the alias while which shows only the underlying program.
command -v is a POSIX-compliant alternative to which that works across all shells:
$ command -v python3
/usr/bin/python3Where Linux Programs Are Installed: Standard Directories
The directories in PATH correspond to standardized locations in the Linux filesystem hierarchy where different categories of programs are installed. Understanding this organization explains why PATH looks the way it does and makes it predictable.
/usr/bin — The Primary Program Location
/usr/bin is the most important directory in PATH for most users. It contains the executable files for the vast majority of user-facing programs installed through the package manager — Firefox, git, Python, GCC, grep, sed, awk, and thousands of others.
$ ls /usr/bin | head -20
[
aa-enabled
aa-exec
aa-features-abi
addpart
addr2line
appstreamcli
apt
apt-cache
apt-cdrom
apt-config
apt-ftparchive
apt-get
apt-key
apt-mark
apt-sortpkgs
ar
arch
aspell
atWhen you install a package with sudo apt install firefox, the package installs the firefox executable into /usr/bin/firefox. Because /usr/bin is in PATH, you can immediately run firefox from the terminal.
$ ls /usr/bin | wc -l
1347On a typical Ubuntu system, over a thousand executable programs live in /usr/bin.
/usr/sbin — System Administration Programs
/usr/sbin (system binaries) contains programs intended primarily for system administrators rather than regular users. Commands like useradd (create user accounts), sshd (the SSH server daemon), fdisk (disk partitioning), and iptables (firewall configuration) live here.
These commands are in PATH for root and for regular users who use sudo, but they are conceptually separated from everyday user programs to signal that they are system management tools.
/bin and /sbin — Legacy Locations (Now Merged)
On older Linux systems, /bin contained essential commands available to all users (like ls, cat, cp, mv, rm, bash), and /sbin contained essential system commands. These needed to be available even if /usr was on a separate filesystem that was not yet mounted during early boot.
On modern distributions (Ubuntu 20.04+, Fedora, Arch), /bin and /sbin are now symbolic links pointing to /usr/bin and /usr/sbin respectively. The contents have been merged. If you run ls -la /bin, you will see it is a symlink:
$ ls -la /bin
lrwxrwxrwx 1 root root 7 Jan 15 08:00 /bin -> usr/binBoth /bin and /usr/bin effectively refer to the same directory.
/usr/local/bin — Locally Installed Programs
/usr/local/bin is the designated location for programs you install locally — outside the package manager’s control. When you compile software from source code and install it manually, the convention is to install it to /usr/local/. When you use language-specific package managers like pip to install programs system-wide, they often go to /usr/local/bin.
/usr/local/bin appears before /usr/bin in most PATH configurations. This ordering means locally installed programs take precedence over distribution-packaged programs of the same name — allowing you to install a newer version of a tool without removing the distribution’s version.
# If both exist:
# /usr/local/bin/python3 (version 3.13, manually installed)
# /usr/bin/python3 (version 3.12, from package manager)
# The locally installed 3.13 runs when you type python3/usr/local/sbin — Locally Installed System Programs
The local equivalent of /usr/sbin — for system administration programs you install manually, outside the package manager.
/home/username/.local/bin — User-Local Programs
~/.local/bin is the per-user equivalent of /usr/local/bin. Programs installed specifically for your user account go here. The Python package manager pip install --user installs command-line tools here. When you install programs with --user flag in various language ecosystems, executables often end up in ~/.local/bin.
This directory appears first in PATH in modern Linux configurations, meaning user-local programs take highest precedence. This allows you to install newer versions of tools for yourself without affecting other users or requiring administrator privileges.
If ~/.local/bin does not exist yet, create it:
$ mkdir -p ~/.local/binIt will automatically be in PATH on next login (on modern Ubuntu and many other distributions).
/snap/bin — Snap Package Programs
On Ubuntu and systems with Snap installed, /snap/bin contains executable links for all installed Snap packages. When you install Firefox as a Snap (sudo snap install firefox), a link named firefox appears in /snap/bin pointing to the actual Snap executable.
Distribution-Specific and Tool-Specific Directories
Beyond the standard directories, specific tools add their own directories to PATH:
/usr/gamesand/usr/local/games— game programs/opt/google/chromeor similar/opt/subdirectories — self-contained commercial applications~/.cargo/bin— Rust programs installed via Cargo~/go/bin— Go programs installed viago install~/.rbenv/binand similar — Ruby version managers~/.nvm/versions/node/*/bin— Node.js version managers
These tool-specific directories are typically added to PATH automatically by their installation scripts.
How PATH Is Set and Modified
PATH is not static — it is built up from multiple sources each time you log in or open a new terminal.
Where PATH Comes From: Configuration Files
PATH is assembled from several shell configuration files, which are read in a specific order depending on how the shell was started.
Login shells (shells started when you first log in, or when you run bash --login) read:
/etc/.profile— system-wide login configuration (applies to all users)/etc/.profile.d/*.sh— additional system-wide configuration scripts~/.profileor~/.bash_profileor~/.bash_login— user-specific login configuration (first one found is used)
Interactive non-login shells (shells started when you open a new terminal window after you are already logged in) read:
/etc/.bash.bash.rc— system-wide interactive shell configuration~/.bash.rc— user-specific interactive shell configuration
On Ubuntu and most modern distributions, ~/.profile typically sources ~/.bash.rc, and both contribute to PATH. The result is that PATH is built up from the system defaults, modified by system-wide scripts in /etc/.profile.d/, and further modified by your personal configuration in ~/.bash.rc and ~/.profile.
Viewing How PATH Is Built
To see where PATH gets its value, look at the relevant configuration files:
$ cat ~/.profile | grep PATH
$ cat ~/.bash.rc | grep PATH
You may also see PATH manipulation scattered throughout /etc/.profile.d/:
$ ls /etc/.profile.d/
apps-bin-pa.th.sh bash_comple.tion.sh cedilla-portugu.ese.sh flat.pak.sh ...
$ cat /etc/.profile.d/apps-bin-path.sh
Each file in /etc/.profile.d/ can add to or modify PATH. Package managers and software installers use this mechanism to add new directories to all users’ PATHs when they install software that needs it.
Viewing Your Current PATH Clearly
The default PATH output is hard to read as a colon-separated string. This command displays each directory on its own line:
$ echo $PATH | tr ':' '\n'
/home/sarah/.local/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/snap/bintr ':' '\n' replaces every colon with a newline, making the list readable.
Adding Directories to PATH
The most practical PATH skill for Linux users is adding a new directory to PATH — making programs in that directory runnable by name from anywhere.
Temporary PATH Modification (Current Session Only)
To add a directory to PATH for the current terminal session only, use the assignment syntax:
$ export PATH="$PATH:/new/directory"Breaking this down:
export— marks the variable for export to child processes (programs you run from this shell)PATH=— assigns a new value to PATH"$PATH:/new/directory"— the new value: your current PATH, followed by a colon, followed by the new directory
After running this, any programs in /new/directory are immediately runnable by name. This change lasts only for the current terminal session — open a new terminal window and the original PATH is restored.
Add to the beginning of PATH (highest priority — overrides existing programs of the same name):
$ export PATH="/new/directory:$PATH"Add to the end of PATH (lowest priority — only used if not found elsewhere):
$ export PATH="$PATH:/new/directory"The position matters: directories earlier in PATH take precedence over later ones.
Permanent PATH Modification
To make a PATH addition permanent — persisting across sessions and reboots — add the export command to a shell configuration file.
For a single user, edit ~/.bash.rc:
$ nano ~/.bash.rcAdd at the end of the file:
export PATH="$PATH:/new/directory"Save and exit. Apply the change to your current session:
$ source ~/.bash.rcOr simply open a new terminal window.
For all users (requires root), add a file to /etc/.profile.d/:
$ sudo nano /etc/.profile.d/custom-pa.th.shAdd:
export PATH="$PATH:/new/directory"This file is automatically read by all users’ login shells.
Adding ~/.local/bin to PATH (If Not Already There)
On some older systems or minimal configurations, ~/.local/bin might not be in PATH by default. Check whether it is:
$ echo $PATH | tr ':' '\n' | grep local
/home/sarah/.local/binIf it does not appear, add it to your ~/.bash.rc:
# Add ~/.local/bin to PATH if it exists
if [ -d "$HOME/.local/bin" ]; then
export PATH="$HOME/.local/bin:$PATH"
fiThe if [ -d ... ] check prevents adding a non-existent directory to PATH (which is harmless but untidy).
Adding Cargo, Go, and Other Tool Binaries
Language-specific tools often provide PATH setup instructions. Rust’s Cargo:
# In ~/.bash.rc or ~/.profile
export PATH="$HOME/.cargo/bin:$PATH"Go programs installed with go install:
export PATH="$HOME/go/bin:$PATH"Node Version Manager (nvm) and Ruby Version Manager (rbenv) have more complex PATH setup that their installers handle automatically.
PATH Security Considerations
PATH is a frequent target in security discussions, and understanding its security implications makes you a more aware Linux user.
The Empty Directory or Dot in PATH
Never include the current directory (.) in PATH. A PATH that includes . (dot, representing the current directory) means the shell will execute programs in whatever directory you are currently in. This is a serious security risk: if a malicious file named ls or sudo or cd is placed in a directory you navigate to, your shell will execute it instead of the real command.
Some older tutorials suggest adding . to PATH for convenience (so you can run ./sc.ript.sh as just sc.ript.sh). Do not do this on any multi-user system. The explicit ./ prefix when running scripts in the current directory is not a burden — it is a clear, intentional security signal that says “I am running this specific file from this location.”
PATH Order and Command Hijacking
Because PATH is searched left to right and the first match wins, an attacker who can write to a directory early in your PATH can place malicious programs there that shadow legitimate ones. This is sometimes called “PATH hijacking.”
For example, if /home/sarah/bin is before /usr/bin in PATH and an attacker places a malicious file at /home/sarah/bin/sudo, running sudo would execute the malicious program rather than the real /usr/bin/sudo.
Protection: keep your PATH clean and ordered sensibly. Do not add writable directories that others can access before system directories in your PATH. Audit your PATH periodically.
sudo and Secure PATH
sudo helps mitigate PATH attacks by using a separate, clean PATH when running commands with elevated privileges. This “secure path” is defined in the sudoers configuration:
$ sudo grep secure_path /etc/.sudoers
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/sbin:/snap/bin"When you run sudo command, the command runs with this clean, fixed PATH rather than your potentially customized user PATH. This means:
- You cannot accidentally run a PATH-hijacked version of a program with sudo
- Programs you have installed in
~/.local/binare not found when running under sudo (you need to use their full path)
Common PATH Problems and Solutions
“Command Not Found” for a Newly Installed Program
You install a program and try to run it, but get “command not found”:
$ my_new_tool
bash: my_new_tool: command not foundStep 1: Find where the program was installed:
$ find /usr -name "my_new_tool" 2>/dev/null
$ find ~/.local -name "my_new_tool" 2>/dev/null
$ find /opt -name "my_new_tool" 2>/dev/nullStep 2: Check whether that directory is in PATH:
$ echo $PATH | tr ':' '\n' | grep /found/directoryStep 3: If not in PATH, add it:
$ export PATH="$PATH:/found/directory" # TemporaryOr add to ~/.bash.rc for permanence.
Step 4: Hash refresh (rare but occasionally needed): If you just installed a program in a directory already in PATH but the shell still cannot find it, Bash may have cached the fact that the command did not exist. Clear the cache:
$ hash -rProgram Works Differently Under sudo
A program runs correctly as your regular user but behaves unexpectedly or is not found when run with sudo:
$ my_tool --version
my_tool version 2.1.0
$ sudo my_tool --version
sudo: my_tool: command not foundThis happens because sudo uses its own secure_path, not your PATH. If my_tool is in ~/.local/bin (not in sudo’s secure path), sudo cannot find it.
Solutions:
Use the full path with sudo:
$ sudo /home/sarah/.local/bin/my_tool --versionOr temporarily preserve your PATH with sudo:
$ sudo env PATH="$PATH" my_tool --versionOr if appropriate, install the program system-wide (in /usr/local/bin) so it is available to all users including under sudo.
PATH Changes Not Persisting
You added a directory to PATH in the terminal but it is gone when you open a new terminal:
- Confirm you edited the correct file (
~/.bash.rcfor interactive terminals on most systems) - Confirm the edit was saved
- Apply the change:
source ~/.bash.rc - Verify:
echo $PATH | tr ':' '\n'
Wrong Version of a Program Running
You have two versions of a program (for example, Python 3.11 and Python 3.12) and the wrong one runs:
$ python3 --version
Python 3.11.9 # But you wanted 3.12Find both:
$ which python3
/usr/bin/python3
$ find /usr/local/bin -name "python3*"
/usr/local/bin/python3.12The one in /usr/bin is running because /usr/bin comes before /usr/local/bin in this hypothetical PATH configuration. To fix:
$ export PATH="/usr/local/bin:$PATH"Now /usr/local/bin is searched first, and python3 there takes precedence.
PATH in Scripts
Shell scripts have their own PATH considerations that differ from interactive shell sessions.
Scripts Do Not Inherit Your Interactive PATH
When a shell script runs, it inherits the environment of the process that started it. If you run a script from a terminal with an interactive PATH, the script gets that PATH. But scripts run by cron, by systemd, or by other services run with a minimal system PATH that often contains only /usr/bin:/bin or similar.
A script that runs successfully from your terminal may fail when run automatically because the program it calls is in /usr/local/bin (which you added to your interactive PATH) but not in the minimal system PATH.
Best practice: Use absolute paths in scripts for reliability:
#!/bin/bash
# Fragile — depends on PATH
python3 process.py
# Robust — absolute path, works regardless of PATH
/usr/bin/python3 process.pyOr set PATH explicitly at the top of scripts meant for automated execution:
#!/bin/bash
PATH="/usr/local/bin:/usr/bin:/bin"
export PATHFinding the Absolute Path for Scripts
$ which python3
/usr/bin/python3
$ which rsync
/usr/bin/rsyncUse these absolute paths in scripts rather than relying on PATH resolution.
Putting It All Together: PATH in Practice
Here is a practical scenario that ties together everything covered in this article.
You have written a collection of useful shell scripts that you want to be able to run from anywhere:
$ ls ~/bin/
back.up.sh clean.up.sh re.port.sh sy.nc.shStep 1: Make them executable:
$ chmod +x ~/bin/*.shStep 2: Remove the .sh extension for cleaner commands (optional):
$ for f in ~/bin/*.sh; do mv "$f" "${f%.sh}"; done
$ ls ~/bin/
backup cleanup report syncStep 3: Add ~/bin to PATH in ~/.bash.rc:
$ nano ~/.bash.rcAdd at the end:
export PATH="$HOME/bin:$PATH"Step 4: Apply the change:
$ source ~/.bash.rcStep 5: Verify:
$ echo $PATH | tr ':' '\n' | head -3
/home/sarah/bin
/home/sarah/.local/bin
/usr/local/sbin
$ which backup
/home/sarah/bin/backupStep 6: Run your scripts from anywhere:
$ cd /tmp
$ backup
Running backup...The script runs successfully from /tmp because the shell found it through PATH, not because you are in the same directory as the script.
PATH Quick Reference
| Task | Command |
|---|---|
| View current PATH | echo $PATH |
| View PATH directories (one per line) | echo $PATH | tr ':' '\n' |
| Find where a command lives | which command |
| See how the shell resolves a name | type command |
| Add directory to PATH (temporary) | export PATH="$PATH:/new/dir" |
| Add directory to front of PATH (priority) | export PATH="/new/dir:$PATH" |
| Apply ~/.bash.rc changes | source ~/.bash.rc |
| Check if a directory is in PATH | echo $PATH | tr ':' '\n' | grep dirname |
| Refresh command hash cache | hash -r |
| Run a script in current directory | ./script.sh (never rely on . in PATH) |
| Use full path in scripts | which command → use that path in script |
Conclusion: PATH Is the Shell’s Address Book
The PATH variable is one of those foundational mechanisms that becomes invisible once you understand it — everything just works, and you know why. Commands are found because the shell knows where to look. Programs are installed in predictable locations. You can extend the system’s reach by adding your own directories. And when something goes wrong, you know exactly how to diagnose and fix it.
The key insights to carry forward are these: PATH is a list of directories, searched in order, left to right. System programs live in /usr/bin and related directories. Locally installed programs belong in /usr/local/bin or ~/.local/bin. Adding a directory to PATH makes its programs runnable by name. And scripts should use absolute paths rather than relying on PATH configuration that may not be present in automated environments.
With PATH understood, the Linux command line becomes more predictable and more powerful. You know not just how to run programs but why the shell finds them — and when it does not, you know exactly where to look.








