Understanding the Linux Path: Where Are My Programs Located?

Learn what the Linux PATH variable is, how the shell finds programs, where commands are installed, and how to add custom directories to your PATH. Beginner-friendly guide.

Understanding the Linux Path: Where Are My Programs Located?

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:

Bash
$ env

This prints a long list. To view a specific variable, use echo with the variable name preceded by $:

Bash
$ echo $HOME
/home/sarah

$ echo $USER
sarah

$ echo $SHELL
/bin/bash

The $ 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:

Bash
$ echo $PATH
/home/sarah/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin

Each 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:

  1. /home/sarah/.local/bin
  2. /usr/local/sbin
  3. /usr/local/bin
  4. /usr/sbin
  5. /usr/bin
  6. /sbin
  7. /bin
  8. /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:

  1. Check if git is a shell built-in command (like cd, echo, pwd). Built-ins are part of the shell itself and do not need to be found in PATH.
  2. Check if git matches an alias or shell function defined in your current session.
  3. Search each directory in PATH, in order:
    • Does /home/sarah/.local/bin/git exist and is it executable? No.
    • Does /usr/local/sbin/git exist and is it executable? No.
    • Does /usr/local/bin/git exist and is it executable? No.
    • Does /usr/sbin/git exist and is it executable? No.
    • Does /usr/bin/git exist and is it executable? Yes.
  4. Run /usr/bin/git with any arguments you provided.

If the shell searches all PATH directories and finds no matching executable, it prints:

Bash
bash: git: command not found

This 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:

Bash
$ which python3
/usr/bin/python3

$ which git
/usr/bin/git

$ which firefox
/usr/bin/firefox

type 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:

Bash
$ 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/git

type 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:

Bash
$ command -v python3
/usr/bin/python3

Where 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.

Bash
$ 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
at

When 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.

Bash
$ ls /usr/bin | wc -l
1347

On 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:

Bash
$ ls -la /bin
lrwxrwxrwx 1 root root 7 Jan 15 08:00 /bin -> usr/bin

Both /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.

Bash
# 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:

Bash
$ mkdir -p ~/.local/bin

It 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/games and /usr/local/games — game programs
  • /opt/google/chrome or similar /opt/ subdirectories — self-contained commercial applications
  • ~/.cargo/bin — Rust programs installed via Cargo
  • ~/go/bin — Go programs installed via go install
  • ~/.rbenv/bin and 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:

  1. /etc/.profile — system-wide login configuration (applies to all users)
  2. /etc/.profile.d/*.sh — additional system-wide configuration scripts
  3. ~/.profile or ~/.bash_profile or ~/.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:

  1. /etc/.bash.bash.rc — system-wide interactive shell configuration
  2. ~/.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:

Bash
$ echo $PATH | tr ':' '\n'
/home/sarah/.local/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/snap/bin

tr ':' '\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:

Bash
$ 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):

Bash
$ export PATH="/new/directory:$PATH"

Add to the end of PATH (lowest priority — only used if not found elsewhere):

Bash
$ 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:

Bash
$ nano ~/.bash.rc

Add at the end of the file:

Bash
export PATH="$PATH:/new/directory"

Save and exit. Apply the change to your current session:

Bash
$ source ~/.bash.rc

Or simply open a new terminal window.

For all users (requires root), add a file to /etc/.profile.d/:

Bash
$ sudo nano /etc/.profile.d/custom-pa.th.sh

Add:

Bash
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:

Bash
$ echo $PATH | tr ':' '\n' | grep local
/home/sarah/.local/bin

If it does not appear, add it to your ~/.bash.rc:

Bash
# Add ~/.local/bin to PATH if it exists
if [ -d "$HOME/.local/bin" ]; then
    export PATH="$HOME/.local/bin:$PATH"
fi

The 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:

Bash
# In ~/.bash.rc or ~/.profile
export PATH="$HOME/.cargo/bin:$PATH"

Go programs installed with go install:

Bash
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:

Bash
$ 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/bin are 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”:

Bash
$ my_new_tool
bash: my_new_tool: command not found

Step 1: Find where the program was installed:

Bash
$ 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/null

Step 2: Check whether that directory is in PATH:

Bash
$ echo $PATH | tr ':' '\n' | grep /found/directory

Step 3: If not in PATH, add it:

Bash
$ export PATH="$PATH:/found/directory"   # Temporary

Or 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:

Bash
$ hash -r

Program Works Differently Under sudo

A program runs correctly as your regular user but behaves unexpectedly or is not found when run with sudo:

Bash
$ my_tool --version
my_tool version 2.1.0

$ sudo my_tool --version
sudo: my_tool: command not found

This 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:

Bash
$ sudo /home/sarah/.local/bin/my_tool --version

Or temporarily preserve your PATH with sudo:

Bash
$ sudo env PATH="$PATH" my_tool --version

Or 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.rc for 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:

Bash
$ python3 --version
Python 3.11.9    # But you wanted 3.12

Find both:

Bash
$ which python3
/usr/bin/python3

$ find /usr/local/bin -name "python3*"
/usr/local/bin/python3.12

The one in /usr/bin is running because /usr/bin comes before /usr/local/bin in this hypothetical PATH configuration. To fix:

Bash
$ 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:

Bash
#!/bin/bash
# Fragile — depends on PATH
python3 process.py

# Robust — absolute path, works regardless of PATH
/usr/bin/python3 process.py

Or set PATH explicitly at the top of scripts meant for automated execution:

Bash
#!/bin/bash
PATH="/usr/local/bin:/usr/bin:/bin"
export PATH

Finding the Absolute Path for Scripts

Bash
$ which python3
/usr/bin/python3

$ which rsync
/usr/bin/rsync

Use 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:

Bash
$ ls ~/bin/
back.up.sh    clean.up.sh    re.port.sh    sy.nc.sh

Step 1: Make them executable:

Bash
$ chmod +x ~/bin/*.sh

Step 2: Remove the .sh extension for cleaner commands (optional):

Bash
$ for f in ~/bin/*.sh; do mv "$f" "${f%.sh}"; done
$ ls ~/bin/
backup    cleanup    report    sync

Step 3: Add ~/bin to PATH in ~/.bash.rc:

Bash
$ nano ~/.bash.rc

Add at the end:

Bash
export PATH="$HOME/bin:$PATH"

Step 4: Apply the change:

Bash
$ source ~/.bash.rc

Step 5: Verify:

Bash
$ echo $PATH | tr ':' '\n' | head -3
/home/sarah/bin
/home/sarah/.local/bin
/usr/local/sbin

$ which backup
/home/sarah/bin/backup

Step 6: Run your scripts from anywhere:

Bash
$ 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

TaskCommand
View current PATHecho $PATH
View PATH directories (one per line)echo $PATH | tr ':' '\n'
Find where a command liveswhich command
See how the shell resolves a nametype 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 changessource ~/.bash.rc
Check if a directory is in PATHecho $PATH | tr ':' '\n' | grep dirname
Refresh command hash cachehash -r
Run a script in current directory./script.sh (never rely on . in PATH)
Use full path in scriptswhich 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.

Share:
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments

Discover More

Rogo Raises $75M Series B for AI-Powered CFO Workflow Platform

Financial automation startup Rogo raises $75 million Series B funding to unify and automate finance…

Understanding the Difference Between System Software and Application Software

Understanding the Difference Between System Software and Application Software

Learn the key differences between system software and application software, how they interact, and why…

The Difference Between Hibernation, Sleep, and Shutdown

Understand the key differences between hibernation, sleep, and shutdown on your computer. Learn how each…

Navigating the iOS Interface: Essential Tips for Beginners

Discover essential tips for navigating the iOS interface. Learn how to manage apps, use Siri…

ServiceNow’s $7.75B Armis Deal Signals a New Era of AI-Driven Cyber Defense

ServiceNow’s Armis acquisition highlights how AI is reshaping enterprise security priorities: visibility, automation, and governance.

ATSC Showcases NextGen TV 3.0 at CES 2026 With New Home Solutions

ATSC will showcase NextGen TV 3.0 receivers and multiunit dwelling solutions at CES 2026, advancing…

Click For More
0
Would love your thoughts, please comment.x
()
x