Reputation: 64756
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?
Upvotes: 23
Views: 27728
Reputation: 72609
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?
Upvotes: 5
Reputation: 107729
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-/))
Upvotes: 51
Reputation: 64756
Still not sure what the problem was (maybe newlines in $PATHDIRS)? but changing to zsh array syntax fixed it:
PATHDIRS=(
/usr/local/mysql/bin
/usr/local/share/python
/usr/local/scala/scala-2.8.0.final/bin
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/bin
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin
/opt/local/etc
/opt/local/bin
/opt/local/sbin
$HOME/.gem/ruby/1.8/bin
$HOME/bin)
and
path=($path $dir)
Upvotes: 3