Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does zsh ignore the PATH entry order?

I am trying to use a very basic setup pattern here: I have two different installations of a given tool (ocamlc, but that does not really matter). In order to select one tool, I attempt to override the PATH variable by prepending an entry.

% where ocamlc     
/home/choeger/ueb/uebb/amsun-integration/Runtime/test_src/../../opam/4.02.3/bin/ocamlc
/home/choeger/.opam/4.02.3/bin/ocamlc
/usr/bin/ocamlc

However, the zsh still uses the older entry:

% ocamlc -v        
The OCaml compiler, version 4.02.3
Standard library directory: /home/choeger/.opam/4.02.3/lib/ocaml

(One can see that it uses the second entry because the library directory is hardcoded to that installation)

Bash behaves as expected:

% bash -c "ocamlc -v"
The OCaml compiler, version 4.02.3
Standard library directory: /home/choeger/ueb/uebb/amsun-integration/opam/4.02.3/lib/ocaml

So why does zsh ignore the first PATH entry although it lists it as first element of where?

edit: In order to verify that zsh does not invoke the same binary, here is another run:

% type -a ocamlc
ocamlc is /home/choeger/ueb/uebb/amsun-integration/tests/pendulum/../../opam/4.02.3/bin/ocamlc
ocamlc is /home/choeger/.opam/4.02.3/bin/ocamlc
ocamlc is /usr/bin/ocamlc
% ocamlc -v
The OCaml compiler, version 4.02.3
Standard library directory: /home/choeger/.opam/4.02.3/lib/ocaml
% /home/choeger/ueb/uebb/amsun-integration/tests/pendulum/../../opam/4.02.3/bin/ocamlc -v
The OCaml compiler, version 4.02.3
Standard library directory: /home/choeger/ueb/uebb/amsun-integration/opam/4.02.3/lib/ocaml

edit2: Here is the setopt output:

% setopt
autocd
autopushd
nobeep
completeinword
correct
extendedglob
extendedhistory
histignorealldups
histignorespace
nohup
interactive
interactivecomments
longlistjobs
monitor
nonomatch
pushdignoredups
shinstdin
zle
% 

Config is the grml config found here plus some path variables in the .local file.

like image 938
choeger Avatar asked Apr 11 '16 08:04

choeger


1 Answers

By default zsh hashes locations of commands the first time they are executed. When executing it a second time the hashed path is used. To refresh the hash table run

rehash

or

hash -r

This should happen automatically every time you change PATH and its main use is, when new executables are added to directories already in PATH.


Note: the following might be overkill for the specific use case. But it also does solve the issue and might be of interest for slightly different use cases.

If you do not care about the (probably negligible) performance hit, you can disable hashing of commands by disabling the HASH_CMDS option:

setopt nohashcmds

While zsh will still be using the hash table, it will not automatically add every command. So, unless a command is entered to the hash table by other means, zsh will check PATH for the command every time.

This might still lead to problems, if the option CORRECT is set. As this does set the hash table in order to provide spelling correction, but will not necessarily refresh it when PATH changes. In order to refresh the table automatically, you can use the precmd hook which is executed each time before the prompt is printed.

autoload -Uz add-zsh-hook
auto_rehash () {
    rehash
}
add-zsh-hook precmd auto_rehash 
like image 114
Adaephon Avatar answered Sep 22 '22 00:09

Adaephon