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?

  • 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
  • 1
    .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 \

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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