468

I'm using zsh terminal, and I'm trying to add a new entry (/home/david/pear/bin) to the PATH variable. I don't see a reference to the PATH variable in my ~/.zshrc file, but doing echo $PATH returns:

/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

So I know that the path variable is being set somewhere. Where is the PATH variable set / modified for the zsh terminal?

Jthorpe
  • 9,756
  • 2
  • 49
  • 64
David Barreto
  • 8,887
  • 7
  • 32
  • 46
  • 15
    In my opinion, PATH should be manipulated in `.zshenv`, not in `.zshrc`... – Rmano Sep 30 '20 at 11:01
  • 12
    In case anyone else is curious about @Rmano's pointer on using '.zshenv' (as I was), here's [link](https://unix.stackexchange.com/questions/71253/what-should-shouldnt-go-in-zshenv-zshrc-zlogin-zprofile-zlogout?newreg=741ab675789d4b1ba96862d40c2bb2d7) a detailed discussion. – YCode Jul 04 '21 at 12:53

13 Answers13

577

Actually, using ZSH allows you to use special mapping of environment variables. So you can simply do:

# append
path+=('/home/david/pear/bin')
# or prepend
path=('/home/david/pear/bin' $path)
# export to sub-processes (make it inherited by child processes)
export PATH

For me that's a very neat feature which can be propagated to other variables. Example:

typeset -T LD_LIBRARY_PATH ld_library_path :
Trevor Hickey
  • 36,288
  • 32
  • 162
  • 271
ony
  • 12,457
  • 1
  • 33
  • 41
  • 35
    Nice answer. In my case, `~/.zshrc` is sourced after `.profile`, and overwrites everything in `.profile`. Took a while pulling my hair to figure it out. – Khanh Nguyen Jun 16 '14 at 23:53
  • 2
    The append case does does not need the parens unless you're appending more than one element. It also often doesn't need the quotes. So the simple, short way to append is – Micah Elliott Jun 11 '15 at 21:54
  • 1
    @SuperUberDuper, you should understand that almost any unix shell simply reads startup files which does almost the same as if you'd type it into shell interactively. Regarding "rc" files you might find interesting answer to [this question](http://unix.stackexchange.com/questions/3467/what-does-rc-in-bashrc-stand-for) – ony Mar 07 '16 at 09:08
  • 13
    It's possible to avoid explicit export with `-x` and leave only unique values in a variable with `-U`, colon is assumed by default, so it can be: `typeset -TUx PATH path` – Grief Mar 16 '17 at 19:53
  • 3
    I see the use of `path` and `PATH`, both are separate entities? – CousinCocaine Nov 07 '19 at 15:09
  • 1
    @CousinCocaine, you are right. ZSH variables are case-sensitive. `typeset -T` allows to tie `PATH` and `path` together in a special way that internally ZSH manages array variable `path` and reflects its contents in `PATH` as a scalar. – ony Nov 17 '19 at 22:53
  • You can even have it as 1-liner: `export path=(... $path)`. – caram Jan 05 '20 at 10:15
  • 1
    This doesn't work for me on my mac. I use the one liner answer below that updates ~/.zshrc insead. – Randy May 05 '20 at 18:02
  • @KhanhNguyen how can I see when these files are sourced? Is there a cmd? – Timo Dec 31 '20 at 10:09
  • 1
    @Timo, in case of zsh you can try something like `zsh -x -i -l -c true` to see all commands during shell start-up. That `-l` is to simulate login-like start (as it happens from text VT or over `ssh`). But you should understand that not always `zsh` will be started as login (e.g. graphical session) and some other parent process may somehow source `.profile` before spawning non-login `zsh` sub-process that inherits environment variables (including `PATH`) from parent process. – ony Jan 01 '21 at 18:37
  • 2
    What if i want to use $HOME inside ' '? path +=('$HOME/etc/etc') doesn't seem to work – Rotkiv Jan 27 '21 at 22:02
  • 1
    @Rotkiv, that's a bit different question about how single/double quotes are interpreted. I guess [zsh expansion](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion) covers this. Usually double-quotes allow string interpolation like `"$HOME/etc/etc"`, but single quotes makes it easier to represent text that should not get special treatment. Note that you can always mix in a single argument forms to have something like `"$HOME"'/etc/etc'` (double + single quotes) or `"$HOME"/etc/etc` (double quotes + unquoted). P.S. Yes I'm lazy to try find link to good answer on SO :P – ony Jan 31 '21 at 21:45
  • On macOS, you can prepend and append to your path variable as described in the post, adding to the .zshrc file. It works without exporting the PATH. – Jost Mar 27 '21 at 13:46
  • If this append or prepend syntax doesn't work for you, make sure that you are using lower case `path`. Lower case `path` is the array. – Yerke Jun 17 '21 at 03:35
  • Thank you for showing the prepend as well! Didn't see it anywhere else. – MEMark Aug 21 '21 at 09:38
  • 1
    This does not seem to work with `~`. – Minh Nghĩa Jan 14 '22 at 06:54
  • 1
    This didn't work for me even though things looked absolutely fine when I `echo $PATH`. I had to go back to the "traditional" syntax of something like: `export PATH=$ANDROID_HOME/platform-tools:$PATH` – Phil Jan 20 '22 at 21:55
  • 1
    @MinhNghĩa, `~` is expanded by shell. If you put it in quotes like `'~/bin'` or `"~/bin"` it will be literally tilda in your path. E.g. you can write `path+=(~/bin)` (note no quotes) or similar. If you need to quote something, you still can do it on part like `path+=(~/'some path with spaces')`. – ony Jan 22 '22 at 17:57
  • @Phil, my best guess for your case is that ok result of `echo $PATH` shows your current shell value for it. Any chance it works if you do `export PATH` (upper case) to export for sub-process after setting `path` (lower case)? – ony Jan 22 '22 at 18:01
  • Append did not work for me. Old school export did. – Boss Man May 16 '23 at 14:19
449

Here, add this line to .zshrc:

export PATH=/home/david/pear/bin:$PATH

EDIT: This does work, but ony's answer above is better, as it takes advantage of the structured interface ZSH provides for variables like $PATH. This approach is standard for bash, but as far as I know, there is no reason to use it when ZSH provides better alternatives.

Michael Lang
  • 3,902
  • 1
  • 23
  • 37
Linuxios
  • 34,849
  • 13
  • 91
  • 116
  • 37
    haha forget it, I though that was only a console command but adding that line to the .zshrc did the trick. Thanks a lot! – David Barreto Jul 17 '12 at 20:42
  • 1
    My .zshrc already had a line for export PATH so I replaced it with the modified one. – Zack Huston Feb 27 '14 at 13:32
  • 6
    I had to remove the double quotes around the entries i.e. `PATH="/home/david/pear/bin:/usr/bin:etc"` to `PATH=/home/david/pear/bin:/usr/bin:etc` for it to stay in zshrc. – a7omiton Feb 07 '15 at 15:01
  • 4
    @taco, you can use $HOME – mencargo Nov 10 '15 at 01:38
  • 1
    It will erase all the old PATH, try `export PATH=$PATH:/path/to/dir` – sstruct Jan 19 '17 at 03:10
  • This appends to my existing PATH, and every time it's run, appends again. How do I set exactly what PATH should be? –  Nov 17 '19 at 23:59
  • You can set `PATH` directly: `export PATH=/some/where:/bin:/usr/bin` and so on. Is that what you're asking? The idea is to run the code in this answer in the `.zshrc` or `.profile` or something like that at the beginning of each session. – Linuxios Nov 18 '19 at 00:01
  • Just a side note, if your path has a space in it. then you need to wrap your path in double quotes like this: ```export PATH=$PATH:"/Applications/Android Studio.app/Contents" ``` – Hamza Waleed Jun 09 '21 at 09:35
113

You can append to your PATH in a minimal fashion. No need for parentheses unless you're appending more than one element. It also usually doesn't need quotes. So the simple, short way to append is:

path+=/some/new/bin/dir

This lower-case syntax is using path as an array, yet also affects its upper-case partner equivalent, PATH (to which it is "bound" via typeset).

(Notice that no : is needed/wanted as a separator.)

Common interactive usage

Then the common pattern for testing a new script/executable becomes:

path+=$PWD/.
# or
path+=$PWD/bin

Common config usage

You can sprinkle path settings around your .zshrc (as above) and it will naturally lead to the earlier listed settings taking precedence (though you may occasionally still want to use the "prepend" form path=(/some/new/bin/dir $path)).

Related tidbits

Treating path this way (as an array) also means: no need to do a rehash to get the newly pathed commands to be found.

Also take a look at vared path as a dynamic way to edit path (and other things).

You may only be interested in path for this question, but since we're talking about exports and arrays, note that arrays generally cannot be exported.

You can even prevent PATH from taking on duplicate entries (refer to this and this):

typeset -U path

PATH pre-populated

The reason your path already has some entries in it is due to your system shell files setting path for you. This is covered in a couple other posts:

Micah Elliott
  • 9,600
  • 5
  • 51
  • 54
  • 1
    @andrewlorien I updated the answer with details about the colon separator. – Micah Elliott Sep 19 '17 at 17:24
  • Note that if there’s a comment after the path, then we do need quotes, like `path+='my/path' # for fun`. It’s obvious if you have spaces, but not so much if you have comments. – Franklin Yu Mar 06 '19 at 15:05
  • 2
    "(Notice that no : is needed/wanted as a separator.)" This is only true for a lowercase `path`. A preceding `:` is required for `PATH`, as follows in .zshrc `PATH+=:/Users/path/to/my/folder` – Emmett R. Jun 18 '20 at 20:55
  • I use a lot `exec zsh` because I work with plugins from `oh-my-zsh`.Everytime I do exec the path gets bigger. Should I "default" the path from time to time? – Timo Oct 15 '20 at 17:31
  • 1
    For ZSH to interpret $PATH as an array and make it unique, I believe the correct way would be `typeset -aU path` – C. Sederqvist Jul 01 '21 at 22:44
71

one liner, without opening ~/.zshrc file

echo -n 'export PATH=~/bin:$PATH' >> ~/.zshrc

or

echo -n 'export PATH=$HOME/bin:$PATH' >> ~/.zshrc

To see the effect, do source ~/.zshrc in the same tab or open a new tab

Siva Praveen
  • 2,213
  • 17
  • 20
37
  1. Added path to ~/.zshrc

    sudo vi ~/.zshrc

    add new path

    export PATH="$PATH:[NEW_DIRECTORY]/bin"
    
  2. Update ~/.zshrc

    Save ~/.zshrc

    source ~/.zshrc

  3. Check PATH

    echo $PATH

saneryee
  • 3,239
  • 31
  • 22
26

OPTION 1: Add this line to ~/.zshrc:

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

After that you need to run source ~/.zshrc in order your changes to take affect OR close this window and open a new one

OPTION 2: execute it inside the terminal console to add this path only to the current terminal window session. When you close the window/session, it will be lost.

Dimitar
  • 1,830
  • 5
  • 32
  • 52
  • Can you elaborate on how this answer is different from [the same answer posted 5 years ago](https://stackoverflow.com/questions/11530090/adding-a-new-entry-to-the-path-variable-in-zsh/11530176#11530176)? – Franklin Yu Mar 06 '19 at 15:28
  • 1
    in this answer it is not said that you have to add this line of code to the file, if you just run it like that it will change only in the current windows and this is not explain in the original answer – Dimitar Mar 06 '19 at 15:40
  • add this to file .zshrc without qoutes export PATH=$HOME/pear/bin:$PATH – Nelson Katale May 14 '23 at 13:33
9

If you are on macOS (I'm on Monterey 12.3.1), you may have been pulling your hair like I did metaphorically. These instructions above all worked for me within the terminal session, but I could never get it to persist no matter what I did with export. Moreover, I couldn't find the .zshrc anywhere.

Turns out Apple does it differently. The file you need to edit is etc/paths. You can simply sudo nano /etc/paths and add your path in a new line. Then simply restart terminal and voila.

MNassar
  • 367
  • 5
  • 11
  • Thank you for that. I've never known why `etc/paths` existed. It's much easier to use than all the export PATH stuff I've used in the past. – jamesnotjim Dec 12 '22 at 03:54
  • This was the only way that worked for me on Monterey. Thanks. – Murrah Dec 22 '22 at 00:01
  • I've been pulling my hair for about 2 hours. I finally found the answer here. Thanks! This worked with Mac OS Monterey 12.5.1 – Mike Diente May 23 '23 at 08:17
2

for me PATH=$PATH:/path/to/file/bin then export PATH worked. to check echo $PATH . other solutions are adding the path temporarily.

Aurora
  • 133
  • 11
2

I'm on Monterey 12.4 and the only way I could change the path was using the helper function. Editing text files in nano did diddly squat

# append
path+=('/foo/bar/yourpath')
# export to sub-processes 
export PATH
jaycer
  • 2,941
  • 2
  • 26
  • 36
1

to verify your new directory has been added correctly, you can use

print -l $path

thanks to the fact that its type is known to be an array

nicolas
  • 9,549
  • 3
  • 39
  • 83
1

You can add new file to /etc/paths.d and you can add your path that file. Don't forget to restart your terminal.

#create new file to /etc/paths.d
touch /etc/paths.d/[filename]
#open created file and add your path
vi /etc/paths.d/[filename]
#save and close file and restart terminal
Enes EREN
  • 11
  • 1
1

A native zsh way is to identify your install directory and create a file from where you will load your PATH modifications:

touch $ZSH/custom/usrenv.zsh

And add the new PATH directories like this inside that usrenv.zsh:

export PATH=$PATH:/home/myself/.foo/bin:/usr/local/bar/bin

The custom directory files *.zsh are sourced by default by the .oh-my-zsh.sh init script, as this snippet taken from it shows:

if [[ -z "$ZSH_CUSTOM" ]]; then
    ZSH_CUSTOM="$ZSH/custom"
fi
...
for config_file ("$ZSH_CUSTOM"/*.zsh(N)); do
  source "$config_file"
done
unset config_file
RicHincapie
  • 3,275
  • 1
  • 18
  • 30
0

The lower case path variable didn't work for me. When I opened up my .zshrc there was already an EXPORT PATH= "$HOME/.local/bin:$PATH", where $PATH is the current path variable set on the machine. All I did was append to the string adding a colon in front of the path. e.g. export PATH="$HOME/.local/bin:$PATH:$HOME/go/bin"`

Anything after the : are the new paths to be appended.

OctaviaLo
  • 1,268
  • 2
  • 21
  • 46