How to Add a Directory to PATH in Linux (Permanent Fix)

Table of Contents
You installed a tool, ran it, and got command not found. You know the binary exists somewhere on your system. You can see it right there when you run ls /home/user/.local/bin/my-tool. But your terminal isn't having it.
This happened to me at least three times before I actually understood what was going on. The fix is adding that directory to your PATH environment variable.
Modern Linux & Terminal Mastery Series
How PATH Actually Works
When you type my-tool in your terminal, your shell doesn't search your entire filesystem. It checks only the directories listed inside the PATH variable, one by one, in order. The moment it finds a match, it stops searching.
Here's what a typical PATH looks like:
/home/user/.local/bin:/usr/local/bin:/usr/bin:/bin
Those colons are separators. So the shell starts by looking in /home/user/.local/bin, then /usr/local/bin, then /usr/bin, and finally /bin. If your tool lives in /home/user/.local/bin and that directory isn't in the list, the shell will never find it.
Sound familiar?
To see your current PATH, run:
echo $PATH
That outputs a colon-separated string. Not very readable, honestly.
To check where a specific command actually comes from:
which <command>
This tells you which executable your shell resolves to, and which directory it's actually finding it in.
Adding a Directory Permanently
Here's where people get lost. There's temporary PATH changes and permanent PATH changes. I confused them for way too long.
Temporary means running export PATH="$PATH:/home/user/.local/bin" directly in your terminal. It works right then. Then you close that terminal, open a new one, and nothing has changed.
Permanent means editing your shell configuration file so the change survives restarts.
The file to edit depends on which shell you're using.
Bash
Edit ~/.bashrc on Linux, or ~/.bash_profile if you're on macOS. Add this line:
export PATH="$PATH:/home/user/.local/bin"
Save the file, then reload it with:
source ~/.bashrc
Or just open a new terminal window. That works too.
Zsh
Edit ~/.zshrc. The line is identical:
export PATH="$PATH:/home/user/.local/bin"
Reload with:
source ~/.zshrc
Fish
Fish is different. It doesn't use the export syntax. Instead, you edit ~/.config/fish/config.fish and add:
fish_add_path /home/user/.local/bin
Here's why I actually like Fish for this: it automatically prevents duplicate entries. And it adds the path to the front of PATH by default, which means your new directory takes priority. That's handy when you want your locally-installed tool to win over a system version.
That 'export' Trick Only Works in That Session
I learned this the hard way. I'd run export PATH="/some/path:$PATH" in my terminal, get excited that it worked, close the window, and wonder why everything reset. If it's not in your config file, it won't persist. Always.
The Mistakes That Kept Tripping Me Up
After helping a few people debug their PATH issues, I've noticed the same problems come up again and again.
The Wrong Program Gets Used
Have you ever installed something and wondered why the old version still runs? Two directories probably both have a program with that name. The one listed first in your PATH wins, every time. Run which <command> and check the path. Is it the one you expected?
If not, you've got a duplicate hiding somewhere.
Permissions Block Everything
This one's obvious in hindsight, but took me an embarrassingly long time to debug. The directory needs to be readable, and the file needs execute permissions. If either one's wrong, your shell will act like the command doesn't exist.
The fix is simple:
chmod +x /path/to/file
Quoting Saves Sanity
Always quote your PATH assignments. This works:
export PATH="$PATH:/home/user/.local/bin"
This breaks silently when paths have spaces:
export PATH=$PATH:/home/user/.local/bin
No error message. Just a broken PATH. The quotes cost you two characters. Use them.
Duplicate Entries Pile Up
If you keep adding export lines to multiple config files, or if you source your config multiple times, you end up with the same directory listed two, three, even five times in your PATH. It's not dangerous, but it's messy.
To find duplicates in your current shell:
echo $PATH | tr ':' '\n' | sort | uniq -d
Fish's fish_add_path handles this automatically. Bash and Zsh users need to be more careful.
A Step-by-Step Workflow That Actually Works
Let me walk you through the process I use now when I hit this problem.
Find where the binary actually lives
If you know the exact path, great. If not, search for it with find ~ -name "my-tool" -type f 2>/dev/null. That searches your home directory for files named "my-tool".
Check if it's already in PATH
Run echo $PATH | tr ':' '\n' | grep -x "/path/you/found". The -x flag means "exact line match". If nothing appears, it's not there yet.
Add it to your shell config
Open the right file for your shell (check with echo $SHELL). Add the appropriate line. For bash/zsh: export PATH="$PATH:/path/you/found". For fish: fish_add_path /path/you/found.
Reload and verify
Run source ~/.bashrc (or your equivalent). Then run which my-tool and confirm it points to the right location.
When Fish Just Feels Right
I started using Fish a couple years ago, mostly because of how it handles PATH. The fish_add_path builtin does exactly what you'd expect, never adds duplicates, and gives you a clean warning if you try to add something that doesn't exist.
Was it worth switching shells just for this? Kind of. The other quality-of-life features kept me there. But if you're happy with bash or zsh, you don't need to switch. Just be more careful with your config files.
The Mental Model That Clicked For Me
Think of PATH like a series of checkpoints. When you type a command, your shell walks down the line, checking each checkpoint in order. First stop: /home/user/.local/bin. Second stop: /usr/local/bin. Third stop: /usr/bin. The first checkpoint that has the executable you want is the one that gets used.
Nothing happens in parallel. Nothing searches the whole building. Just a sequential walk down a list.
Once that clicked, everything about PATH made sense to me.
PATH Order Matters More Than You Think
When two programs share a name, the one in the earlier PATH directory wins. Want your locally-installed version to run instead of the system version? Put your directory first in PATH. Want the system version to be the default? Put it last, or don't add your local directory at all.
Quick Reference
| Shell | Config File | Command |
|---|---|---|
| Bash | ~/.bashrc | export PATH="$PATH:/new/path" |
| Zsh | ~/.zshrc | export PATH="$PATH:/new/path" |
| Fish | ~/.config/fish/config.fish | fish_add_path /new/path |
Wrapping Up
PATH confusion is one of those problems that feels mysterious until it clicks. Once you understand the checkpoint analogy, everything else falls into place.
Open ~/.bashrc (for Bash) or ~/.zshrc (for Zsh) in a text editor, add export PATH="$PATH:/your/directory/path" at the end of the file, save, and run source ~/.bashrc to reload your terminal session.
Running export PATH=... directly in the command line only sets the variable for the current shell process. To make it persistent across all future terminal windows, you must add the export line to your shell configuration file (~/.bashrc or ~/.zshrc).
Prepend (export PATH="/custom/bin:$PATH") if you want your custom binary to override system versions of the same tool. Append (export PATH="$PATH:/custom/bin") if you want system binaries to maintain execution priority.
You Might Also Like
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles

Unwritten Rules of Terminal Programs
Why 'q' quits almost everything, how Ctrl-C became a universal kill switch, and the POSIX ghosts that make the command line feel like home.
Read more
eBPF in Production: Low-Overhead Linux Observability, Tracing, and Kernel Profiling
Implement low-overhead Linux kernel observability using eBPF. Profile system call latency, track memory allocations, and monitor network sockets without sidecars.
Read more
Ubuntu Server Security: The Pragmatic Linux Hardening Checklist
Production Ubuntu server hardening guide: SSH key enforcement, UFW firewalls, Fail2ban intrusion prevention, unattended upgrades, and auditd logging.
Read more