Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

For some reason, my $PATH variable is not being set properly which means I can't run a lot of commands I would like to. Here are the relevant lines from my .zshrc file:

if [[ -f ~/.profile]]; then
    source ~/.profile

Here is my .profile file:


for dir in $pathdirs; do
    if [[ -d $dir ]]; then

When I echo my $PATH variable, none of these three items shows up. All I get when I run cat $PATH is /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/git/bin: /usr/texbin. Could anyone see if I'm doing something wrong?

share|improve this question
Hmm not sure what you mean. My .zshrc is run every time a new shell is open. Within my .zshrc, I have a statement that loads my .profile where I keep all of my $PATH related needs. What's the confusion? – Cody Ma Apr 28 '14 at 2:07
What does putting a echo $dir right before path+=... show you? – slm Apr 28 '14 at 2:46
Please don't cat $PATH... That sounds dangerous – mikeserv Apr 28 '14 at 3:39
In bash at least, you need to do path+=($dir) rather than path+=$dir. – Mikel Apr 28 '14 at 3:48
.profile is traditionally read by all Bourne/POSIX-compliant shells. In which case you'd need "${pathdirs[@]}" rather than $pathdirs. – Mikel Apr 28 '14 at 3:51

Here's a function I wrote for another answer:

_path_assign() { oFS=$IFS ; IFS=: ; add=$* ; unset P A ; A=
    set -- ${PATH:=$1} ; for p in $add ; do {
        [ -z "${p%-[AP]}" ] && { unset P A
                eval ${p#-}= ; continue ; }
        for d ; do [ -z "${d%"$p"}" ] && break
        done ; } || set -- ${P+$p} $* ${A+$p}
        done ; export PATH="$*" ; IFS=$oFS

% PATH=/usr/bin:/usr/yes/bin
% _path_assign \
    /usr/bin \
    /usr/yes/bin \
    /usr/bin/nope \
    -P \
    /usr/nope/bin \
    /usr/bin \
    -A \
    /nope/usr/bin \

% echo $PATH



All arguments following a -P are prepended to $PATH if they are not already included, and same for -A but they're appended. If you want to verify they're actual directories first you can change:

|| set -- ${P+$p} $* ${A+$p}


|| { [ -d "$p" ] && set -- ${P+$p} $* ${A+$p}
} ; done

You should probably make sure zsh handles $IFS more portably by just adding:

[ "${SHELL##*/}" = "zsh" ] && emulate sh

to the first line.

Make those two changes and all of the code you have in your question could be replaced with this function and:

test -f ~/.profile && . $_
_path_assign ~/.rvm/bin \
    /usr/local/heroku/bin \
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.