538

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?

2
  • 17
    In my opinion, PATH should be manipulated in .zshenv, not in .zshrc... Commented Sep 30, 2020 at 11:01
  • 14
    In case anyone else is curious about @Rmano's pointer on using '.zshenv' (as I was), here's link a detailed discussion. Commented Jul 4, 2021 at 12:53

15 Answers 15

664

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)
# and don't forget to export to 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

This is what man zshbuiltins reports about -T.

-T [ scalar[=value] array[=(value ...)] [ sep ] ]
    This flag has a different meaning when used with -f; see below.  Otherwise
    the -T option requires zero, two,  or  three  argu ments  to  be  present.
    With no arguments, the list of parameters created in this fashion is shown.
    With two or three arguments, the first two are the name of a scalar and of
    an array parameter (in that order) that will be tied together in the manner
    of $PATH and $path. The optional third argument is a single-character
    separator which will be used to join  the  elements of the array to form
    the scalar; if absent, a colon is used, as with $PATH. Only the first
    character of the separator is significant;
    any remaining characters are ignored.
    Multibyte characters are not yet supported.
Sign up to request clarification or add additional context in comments.

31 Comments

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.
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
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
I see the use of path and PATH, both are separate entities?
@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.
|
511

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.

10 Comments

haha forget it, I though that was only a console command but adding that line to the .zshrc did the trick. Thanks a lot!
My .zshrc already had a line for export PATH so I replaced it with the modified one.
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.
@taco, you can use $HOME
It will erase all the old PATH, try export PATH=$PATH:/path/to/dir
|
121

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:

6 Comments

@andrewlorien I updated the answer with details about the colon separator.
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.
"(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
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?
For ZSH to interpret $PATH as an array and make it unique, I believe the correct way would be typeset -aU path
|
74

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

Comments

42
  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

1 Comment

This is the Bash way.
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.

3 Comments

Can you elaborate on how this answer is different from the same answer posted 5 years ago?
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
add this to file .zshrc without qoutes export PATH=$HOME/pear/bin:$PATH
11

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.

4 Comments

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.
This was the only way that worked for me on Monterey. Thanks.
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
Worked for me on Ventura
3

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

Comments

2

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

Comments

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

Comments

1

To try to help I will show you how to do the process using a BASH script.

IMPORTANT: The "PATH" environment variable must receive in its configuration a folder (eg: "/home/<YOUR_USER>/.scripts/zsh") and not a binary or script directly (eg: "/home/<YOUR_USER>/.scripts/zsh/my_bash_script").


Install a BASH script as an integrated terminal command

Make the BASH script executable

Run the following command to make "my_bash_script" script executable...

chmod +x /home/<YOUR_USER>/.scripts/zsh/my_bash_script

Add the BASH script to the PATH

Run the following command to temporarily add the BASH script directory to your "PATH"...

export PATH=$PATH:/home/<YOUR_USER>/.scripts/zsh  # Logged in as your user!

Add this line to the end of your ".zshrc" file so that it's automatically added each time you start a terminal session...

echo 'export PATH=$PATH:/home/<YOUR_USER>/.scripts/zsh' >> ~/.zshrc

Reload the ".zshrc" File

To apply the changes immediately, run...

source ~/.zshrc  # Logged in as your user!

Set Permissions

Next, you'll need to ensure that the BASH script have the correct permissions...

chown -R <YOUR_USER>:<YOUR_USER> /home/<YOUR_USER>/.scripts/zsh
chmod -R 700 /home/<YOUR_USER>/.scripts/zsh

You're Done! 😎

Comments

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.

Comments

0

The best way to keep things simple is writing a function and that will only add to your path if given dir exists.

# To avoid duplicates in your $PATH, you can utilize zsh's array features:
# typeset -aU path: This ensures that the path array (which mirrors the $PATH
# environment variable) only contains unique elements.
typeset -aU path

# Function to append the directory to the path array.
export_to_path() {
  local dir="$1"
  if [[ -d "$dir" ]]; then
    # Append the directory to the path array.
    path=("$dir" $path)
}

# Then every time you want to append any path to $PATH just call this function with the path argument.
export_to_path "$HOMEBREW_PREFIX/opt/[email protected]/bin"

Comments

-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

1 Comment

This answers a completely different question.
-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**

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.