ĺŚä˝ĺ°çŽĺ˝ćˇťĺ ĺ° PATH ä¸
Source: Julia Evans
I was talking to a friend about how to add a directory to your PATH today. Itâs
something that feels âobviousâ to me since Iâve been using the terminal for a
long time, but when I searched for instructions for how to do it, I actually
couldnât find something that explained all of the steps â a lot of them just
said âadd this to ~/.bashrcâ, but what if youâre not using bash? What if your
bash config is actually in a different file? And how are you supposed to figure
out which directory to add anyway?
So I wanted to try to write down some more complete directions and mention some of the gotchas Iâve run into over the years.
Hereâs a table of contents:
- step 1: what shell are you using?
- step 2: find your shellâs config file
- step 3: figure out which directory to add
- step 4: edit your shell config
- step 5: restart your shell
- problems:
- notes:
step 1: what shell are you using?
If youâre not sure what shell youâre using, hereâs a way to find out. Run this:
ps -p $$ -o pid,comm=
- if youâre using bash, itâll print out
97295 bash - if youâre using zsh, itâll print out
97295 zsh - if youâre using fish, itâll print out an error like âIn fish, please use
$fish_pidâ (
$$isnât valid syntax in fish, but in any case the error message tells you that youâre using fish, which you probably already knew)
Also bash is the default on Linux and zsh is the default on Mac OS (as of 2024). Iâll only cover bash, zsh, and fish in these directions.
step 2: find your shellâs config file
- in zsh, itâs probably
~/.zshrc - in bash, it might be
~/.bashrc, but itâs complicated, see the note in the next section - in fish, itâs probably
~/.config/fish/config.fish(you can runecho $__fish_config_dirif you want to be 100% sure)
a note on bashâs config file
Bash has three possible config files: ~/.bashrc, ~/.bash_profile, and ~/.profile.
If youâre not sure which one your system is set up to use, Iâd recommend testing this way:
- add
echo hi thereto your~/.bashrc - Restart your terminal
- If you see âhi thereâ, that means
~/.bashrcis being used! Hooray! - Otherwise remove it and try the same thing with
~/.bash_profile - You can also try
~/.profileif the first two options donât work.
(there are a lot of elaborate flow charts out there that explain how bash decides which config file to use but IMO itâs not worth it to internalize them and just testing is the fastest way to be sure)
step 3: figure out which directory to add
Letâs say that youâre trying to install and run a program called http-server
and it doesnât work, like this:
$ npm install -g http-server
$ http-server
bash: http-server: command not found
How do you find what directory http-server is in? Honestly in general this is
not that easy â often the answer is something like âit depends on how npm is
configuredâ. A few ideas:
- Often when setting up a new installer (like
cargo,npm,homebrew, etc), when you first set it up itâll print out some directions about how to update your PATH. So if youâre paying attention you can get the directions then. - Sometimes installers will automatically update your shellâs config file
to update your
PATHfor you - Sometimes just Googling âwhere does npm install things?â will turn up the answer
- Some tools have a subcommand that tells you where theyâre configured to
install things, like:
- Node/npm:
npm config get prefix(then append/bin/) - Go:
go env GOPATH(then append/bin/) - asdf:
asdf info | grep ASDF_DIR(then append/bin/and/shims/)
- Node/npm:
step 3.1: double check itâs the right directory
Once youâve found a directory you think might be the right one, make sure itâs
actually correct! For example, I found out that on my machine, http-server is
in ~/.npm-global/bin. I can make sure that itâs the right directory by trying to
run the program http-server in that directory like this:
$ ~/.npm-global/bin/http-server
Starting up http-server, serving ./public
It worked! Now that you know what directory you need to add to your PATH,
letâs move to the next step!
step 4: edit your shell config
Now we have the 2 critical pieces of information we need:
- Which directory youâre trying to add to your PATH (like
~/.npm-global/bin/) - Where your shellâs config is (like
~/.bashrc,~/.zshrc, or~/.config/fish/config.fish)
Now what you need to add depends on your shell:
bash instructions:
Open your shellâs config file, and add a line like this:
export PATH=$PATH:~/.npm-global/bin/
(obviously replace ~/.npm-global/bin with the actual directory youâre trying to add)
zsh instructions:
You can do the same thing as in bash, but zsh also has some slightly fancier syntax you can use if you prefer:
path=(
$path
~/.npm-global/bin
)
fish instructions:
In fish, the syntax is different:
set PATH $PATH ~/.npm-global/bin
(in fish you can also use fish_add_path, some notes on that further down)
step 5: restart your shell
Now, an extremely important step: updating your shellâs config wonât take effect if you donât restart it!
Two ways to do this:
- open a new terminal (or terminal tab), and maybe close the old one so you donât get confused
- Run
bashto start a new shell (orzshif youâre using zsh, orfishif youâre using fish)
Iâve found that both of these usually work fine.
And you should be done! Try running the program you were trying to run and hopefully it works now.
If not, here are a couple of problems that you might run into:
problem 1: it ran the wrong program
If the wrong version of a program is running, you might need to add the directory to the beginning of your PATH instead of the end.
For example, on my system I have two versions of python3 installed, which I
can see by running which -a:
$ which -a python3
/usr/bin/python3
/opt/homebrew/bin/python3
The one your shell will use is the first one listed.
If you want to use the Homebrew version, you need to add that directory
(/opt/homebrew/bin) to the beginning of your PATH instead, by putting this in
your shellâs config file (itâs /opt/homebrew/bin/:$PATH instead of the usual $PATH:/opt/homebrew/bin/)
export PATH=/opt/homebrew/bin/:$PATH
or in fish:
set PATH ~/.cargo/bin $PATH
problem 2: the program isnât being run from your shell
All of these directions only work if youâre running the program from your shell. If youâre running the program from an IDE, from a GUI, in a cron job, or some other way, youâll need to add the directory to your PATH in a different way, and the exact details might depend on the situation.
in a cron job
Some options:
- use the full path to the program youâre running, like
/home/bork/bin/my-program - put the full PATH you want as the first line of your crontab (something like
PATH=/bin:/usr/bin:/usr/local/bin:âŚ.). You can get the full PATH youâre
using in your shell by running
echo "PATH=$PATH".
Iâm honestly not sure how to handle it in an IDE/GUI because I havenât run into that in a long time, will add directions here if someone points me in the right direction.
problem 3: duplicate PATH entries making it harder to debug
If you edit your path and start a new shell by running bash (or zsh, or
fish), youâll often end up with duplicate PATH entries, because the shell
keeps adding new things to your PATH every time you start your shell.
Personally I donât think Iâve run into a situation where this kind of
duplication breaks anything, but the duplicates can make it harder to debug
whatâs going on with your PATH if youâre trying to understand its contents.
Some ways you could deal with this:
- If youâre debugging your
PATH, open a new terminal to do it in so you get a âfreshâ state. This should avoid the duplication. - Deduplicate your
PATHat the end of your shellâs config (for example in zsh apparently you can do this withtypeset -U path) - Check that the directory isnât already in your
PATHwhen adding it (for example in fish I believe you can do this withfish_add_path --path /some/directory)
How to deduplicate your PATH is shell-specific and there isnât always a
built in way to do it so youâll need to look up how to accomplish it in your
shell.
problem 4: losing your history after updating your PATH
Hereâs a situation thatâs easy to get into in bash or zsh:
- Run a command (it fails)
- Update your
PATH - Run
bashto reload your config - Press the up arrow a couple of times to rerun the failed command (or open a new terminal)
- The failed command isnât in your history! Why not?
This happens because in bash, by default, history is not saved until you exit the shell.
Some options for fixing this:
- Instead of running
bashto reload your config, runsource ~/.bashrc(orsource ~/.zshrcin zsh). This will reload the config inside your current session. - Configure your shell to continuously save your history instead of only saving the history when the shell exits. (How to do this depends on whether youâre using bash or zsh, the history options in zsh are a bit complicated and Iâm not exactly sure what the best way is)
a note on source
When you install cargo (Rustâs installer) for the first time, it gives you
these instructions for how to set up your PATH, which donât mention a specific
directory at all.
This is usually done by running one of the following (note the leading DOT):
. "$HOME/.cargo/env" # For sh/bash/zsh/ash/dash/pdksh
source "$HOME/.cargo/env.fish" # For fish
The idea is that you add that line to your shellâs config, and their script
automatically sets up your PATH (and potentially other things) for you.
This is pretty common (for example Homebrew suggests you eval brew shellenv), and there are
two ways to approach this:
- Just do what the tool suggests (like adding
. "$HOME/.cargo/env"to your shellâs config) - Figure out which directories the script theyâre telling you to run would add
to your PATH, and then add those manually. Hereâs how Iâd do that:
- Run
. "$HOME/.cargo/env"in my shell (or the fish version if using fish) - Run
echo "$PATH" | tr ':' '\n' | grep cargoto figure out which directories it added - See that it says
/Users/bork/.cargo/binand shorten that to~/.cargo/bin - Add the directory
~/.cargo/binto PATH (with the directions in this post)
- Run
I donât think thereâs anything wrong with doing what the tool suggests (it might be the âbest wayâ!), but personally I usually use the second approach because I prefer knowing exactly what configuration Iâm changing.
a note on fish_add_path
fish has a handy function called fish_add_path that you can run to add a directory to your PATH like this:
fish_add_path /some/directory
This is cool (itâs such a simple command!) but Iâve stopped using it for a couple of reasons:
- Sometimes
fish_add_pathwill update thePATHfor every session in the future (with a âuniversal variableâ) and sometimes it will update thePATHjust for the current session and itâs hard for me to tell which one it will do. In theory the docs explain this but I could not understand them. - If you ever need to remove the directory from your
PATHa few weeks or months later because maybe you made a mistake, itâs kind of hard to do (there are instructions in this comments of this github issue though).
thatâs all
Hopefully this will help some people. Let me know (on Mastodon or Bluesky) if you there are other major gotchas that have tripped you up when adding a directory to your PATH, or if you have questions about this post!