Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to edit path variable in ZSH

Tags:

In my .bash_profile I have the following lines:

PATHDIRS=" /usr/local/mysql/bin /usr/local/share/python /opt/local/bin /opt/local/sbin $HOME/bin" for dir in $PATHDIRS do     if [ -d $dir ]; then         export PATH=$PATH:$dir     fi done 

However I tried copying this to my .zshrc, and the $PATH is not being set.

First I put echo statements inside the "if directory exists" function and I found that the if statement was evaluating to false, even for directories that clearly existed.

Then I removed the directory-exists check, and the $PATH was being set incorrectly like this:

/usr/bin:/bin:/usr/sbin:/sbin: /usr/local/bin /opt/local/bin /opt/local/sbin /Volumes/Xshare/kburke/bin /usr/local/Cellar/ruby/1.9.2-p290/bin /Users/kevin/.gem/ruby/1.8/bin /Users/kevin/bin 

None of the programs in the bottom directories were being found or executed.
What am I doing wrong?

like image 670
Kevin Burke Avatar asked Feb 19 '12 07:02

Kevin Burke


People also ask

What is the path in zsh?

PATH is an environment variable where you tell your system to look for executables when you enter a command in the shell. You can inspect the value of the PATH variable by running the following. This outputs a string with locations like /usr/bin and /bin .

Where is zsh path on Mac?

zshrc file on a Mac? The . zshrc file will be located in the users home directory, or ~/, and this user . zshrc file is where you'd place customizations to the z shell.


2 Answers

Unlike other shells, zsh does not perform word splitting or globbing after variable substitution. Thus $PATHDIRS expands to a single string containing exactly the value of the variable, and not to a list of strings containing each separate whitespace-delimited piece of the value.

Using an array is the best way to express this (not only in zsh, but also in ksh and bash).

pathdirs=(     /usr/local/mysql/bin     …     ~/bin ) for dir in $pathdirs; do     if [ -d $dir ]; then         path+=$dir     fi done 

Since you probably aren't going to refer to pathdirs later, you might as well write it inline:

for dir in \   /usr/local/mysql/bin \   … \   ~/bin ; do   if [[ -d $dir ]]; then path+=$dir; fi done 

There's even a shorter way to express this: add all the directories you like to the path array, then select the ones that exist.

path+=/usr/local/mysql/bin … path=($^path(N)) 

The N glob qualifier selects only the matches that exist. Add the -/ to the qualifier list (i.e. (-/N) or (N-/)) if you're worried that one of the elements may be something other than a directory or a symbolic link to one (e.g. a broken symlink). The ^ parameter expansion flag ensures that the glob qualifier applies to each array element separately.

You can also use the N qualifier to add an element only if it exists. Note that you need globbing to happen, so path+=/usr/local/mysql/bin(N) wouldn't work.

path+=(/usr/local/bin/mysql/bin(N-/)) 
like image 104
Gilles 'SO- stop being evil' Avatar answered Sep 20 '22 12:09

Gilles 'SO- stop being evil'


You can put

 setopt shwordsplit 

in your .zshrc. Then zsh will perform world splitting like all Bourne shells do. That the default appears to be noshwordsplit is a misfeature that causes many a head scratching. I'd be surprised if it wasn't a FAQ. Lets see... yup: http://zsh.sourceforge.net/FAQ/zshfaq03.html#l18 3.1: Why does $var where var="foo bar" not do what I expect?

like image 39
Jens Avatar answered Sep 17 '22 12:09

Jens