PATH="/custom/dir:$PATH" prepending instead of appending – Conda vs Pyenv
Question:
I have a Mac (latest software update) with Pyenv and Anaconda. I manage packages with Homebrew and have installed Python 3 with it. When I echo $PATH
I get the following:
/Library/Frameworks/Python.framework/Versions/3.8/bin:
/usr/local/bin:
/usr/bin:
/bin:
/usr/local/sbin:
/usr/sbin:
/sbin:
/Library/TeX/texbin:
/Users/luca/.pyenv/versions/anaconda3-2020.02/condabin:
/Users/luca/.pyenv/versions/3.8.5/bin:
/Users/luca/.pyenv/bin
-
I do not know what sets up /Library/Frameworks/Python.framework/Versions/3.8/bin
: this directory is non-existent on my Mac. I had previously installed Python without Homebrew that is why the directory was created. I did remove that, but there is still something that exports that line in $PATH
, but I cannot find it! Does someone have a guess? I did try and grep -r /*
it, but that is too much of a search for my laptop to finish.
-
I set up in my .zshenv
the code for initialising pyenv
and conda
. Of course, I did write PATH="/dir/to/conda/bin:$PATH"
and the same for pyenv
(see code below). I do not understand why, but they end up at the end of $PATH
. Does someone know why? Is it because of eval "$(pyenv init -)"
being evaluated before conda
?
# >>> pyenv initialize
export PYENV_SHELL=$SHELL
export PATH="/Users/luca/.pyenv/bin:$PATH"
export PATH="/Users/luca/.pyenv/versions/3.8.5/bin:$PATH" #export Python 3.8 bin directory
if command -v pyenv 1>/dev/null 2>&1; then
eval "$(pyenv init -)"
fi
# <<< pyenv initialize <<<
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/luca/.pyenv/versions/anaconda3-2020.02/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/Users/luca/.pyenv/versions/anaconda3-2020.02/etc/profile.d/conda.sh" ]; then
. "/Users/luca/.pyenv/versions/anaconda3-2020.02/etc/profile.d/conda.sh"
else
export PATH="/Users/luca/.pyenv/versions/anaconda3-2020.02/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<
Answers:
I have the exact same problem, and I could not find any other source on why the conda environment gets appended instead of prepended. I have added the following code to my .bash_profile (after conda initialisation) which flips the order of all path location. This is definitely a terrible practice, but it might be a quick fix for someone who is stuck on the same problem.
locations=($(echo $PATH | tr ":" "n"))
path=""
for (( idx=${#locations[@]}-2 ; idx>=0 ; idx-- )) ; do
# Skip the last path location since this would put the general /Users/XXX/opt/anaconda3/condabin first
# To not do this change the -2 to -1
path="${path}:${locations[$idx]}"
done
path="${path:1}"
PATH=$path
export $PATH
As noted in the comment, I do not add the location "/Users/XXX/opt/anaconda3/condabin", since it would mess up my environment location, which is located second to last. Please examine your own path variable and decide accordingly.
EDIT: If anyone has a better solution, please let me know!
TL;DR
In macOS, if you place any code that modifies $PATH
on macOS inside .zshenv
, it will be overridden. You should put it in .zshrc
or somewhere else which is then sourced by your .zshrc
.
Complete explanation
As answered on Unix & Linux Stack Exchange, when zsh is sourced, files are read in the following order:
etc/zshenv/
-> $ZDOTDIR/.zshenv/
-> etc/zprofile/
-> $ZDOTDIR/.zprofile/
-> etc/zshrc/
-> $ZDOTDIR/.zshrc/
-> etc/zlogin/
-> $ZDOTDIR/.zlogin/
In macOS’s /etc/zprofile
, a script is sourced that overrides the $PATH according to the contents of these files:
/etc/paths
/etc/paths.d
/etc/manpaths
/etc/manpaths.d
So you should put not put any line that changes $PATH
in your $ZDOTDIR/.zshenv
, but rather in any file sourced after that (e.g. $ZDOTDIR/.zshrc
). Do not edit files in /etc/
!
I have a Mac (latest software update) with Pyenv and Anaconda. I manage packages with Homebrew and have installed Python 3 with it. When I echo $PATH
I get the following:
/Library/Frameworks/Python.framework/Versions/3.8/bin:
/usr/local/bin:
/usr/bin:
/bin:
/usr/local/sbin:
/usr/sbin:
/sbin:
/Library/TeX/texbin:
/Users/luca/.pyenv/versions/anaconda3-2020.02/condabin:
/Users/luca/.pyenv/versions/3.8.5/bin:
/Users/luca/.pyenv/bin
-
I do not know what sets up
/Library/Frameworks/Python.framework/Versions/3.8/bin
: this directory is non-existent on my Mac. I had previously installed Python without Homebrew that is why the directory was created. I did remove that, but there is still something that exports that line in$PATH
, but I cannot find it! Does someone have a guess? I did try andgrep -r /*
it, but that is too much of a search for my laptop to finish. -
I set up in my
.zshenv
the code for initialisingpyenv
andconda
. Of course, I did writePATH="/dir/to/conda/bin:$PATH"
and the same forpyenv
(see code below). I do not understand why, but they end up at the end of$PATH
. Does someone know why? Is it because ofeval "$(pyenv init -)"
being evaluated beforeconda
?
# >>> pyenv initialize
export PYENV_SHELL=$SHELL
export PATH="/Users/luca/.pyenv/bin:$PATH"
export PATH="/Users/luca/.pyenv/versions/3.8.5/bin:$PATH" #export Python 3.8 bin directory
if command -v pyenv 1>/dev/null 2>&1; then
eval "$(pyenv init -)"
fi
# <<< pyenv initialize <<<
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/luca/.pyenv/versions/anaconda3-2020.02/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/Users/luca/.pyenv/versions/anaconda3-2020.02/etc/profile.d/conda.sh" ]; then
. "/Users/luca/.pyenv/versions/anaconda3-2020.02/etc/profile.d/conda.sh"
else
export PATH="/Users/luca/.pyenv/versions/anaconda3-2020.02/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<
I have the exact same problem, and I could not find any other source on why the conda environment gets appended instead of prepended. I have added the following code to my .bash_profile (after conda initialisation) which flips the order of all path location. This is definitely a terrible practice, but it might be a quick fix for someone who is stuck on the same problem.
locations=($(echo $PATH | tr ":" "n"))
path=""
for (( idx=${#locations[@]}-2 ; idx>=0 ; idx-- )) ; do
# Skip the last path location since this would put the general /Users/XXX/opt/anaconda3/condabin first
# To not do this change the -2 to -1
path="${path}:${locations[$idx]}"
done
path="${path:1}"
PATH=$path
export $PATH
As noted in the comment, I do not add the location "/Users/XXX/opt/anaconda3/condabin", since it would mess up my environment location, which is located second to last. Please examine your own path variable and decide accordingly.
EDIT: If anyone has a better solution, please let me know!
TL;DR
In macOS, if you place any code that modifies $PATH
on macOS inside .zshenv
, it will be overridden. You should put it in .zshrc
or somewhere else which is then sourced by your .zshrc
.
Complete explanation
As answered on Unix & Linux Stack Exchange, when zsh is sourced, files are read in the following order:
etc/zshenv/
-> $ZDOTDIR/.zshenv/
-> etc/zprofile/
-> $ZDOTDIR/.zprofile/
-> etc/zshrc/
-> $ZDOTDIR/.zshrc/
-> etc/zlogin/
-> $ZDOTDIR/.zlogin/
In macOS’s /etc/zprofile
, a script is sourced that overrides the $PATH according to the contents of these files:
/etc/paths
/etc/paths.d
/etc/manpaths
/etc/manpaths.d
So you should put not put any line that changes $PATH
in your $ZDOTDIR/.zshenv
, but rather in any file sourced after that (e.g. $ZDOTDIR/.zshrc
). Do not edit files in /etc/
!