为什么 zsh 会忽略 PATH 入口顺序?

cho*_*ger 6 shell command zsh resolution path

我在这里尝试使用一个非常基本的设置模式:我有两个不同的给定工具安装(ocamlc,但这并不重要)。为了选择一个工具,我尝试通过添加一个条目来覆盖 PATH 变量。

% 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
Run Code Online (Sandbox Code Playgroud)

但是,zsh 仍然使用旧条目:

% ocamlc -v        
The OCaml compiler, version 4.02.3
Standard library directory: /home/choeger/.opam/4.02.3/lib/ocaml
Run Code Online (Sandbox Code Playgroud)

(可以看到它使用了第二个条目,因为库目录是硬编码到该安装的)

Bash 的行为符合预期:

% 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
Run Code Online (Sandbox Code Playgroud)

那么为什么 zsh 忽略第一个 PATH 条目,尽管它将它列为的第一个元素where

编辑:为了验证 zsh 没有调用相同的二进制文件,这里是另一个运行:

% 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
Run Code Online (Sandbox Code Playgroud)

edit2:这是 setopt 输出:

% setopt
autocd
autopushd
nobeep
completeinword
correct
extendedglob
extendedhistory
histignorealldups
histignorespace
nohup
interactive
interactivecomments
longlistjobs
monitor
nonomatch
pushdignoredups
shinstdin
zle
% 
Run Code Online (Sandbox Code Playgroud)

Config 是此处找到的 grml 配置以及 .local 文件中的一些路径变量。

Ada*_*hon 9

默认情况下zsh,第一次执行命令时会散列命令的位置。第二次执行时,使用散列路径。刷新哈希表运行

rehash
Run Code Online (Sandbox Code Playgroud)

或者

hash -r
Run Code Online (Sandbox Code Playgroud)

每次更改时都会自动发生这种情况PATH,其主要用途是将新的可执行文件添加到PATH.


注意:对于特定用例,以下内容可能有点矫枉过正。但它也确实解决了这个问题,并且可能对稍微不同的用例感兴趣。

如果您不关心(可能可以忽略不计)性能影响,您可以通过禁用该HASH_CMDS选项来禁用命令散列:

setopt nohashcmds
Run Code Online (Sandbox Code Playgroud)

虽然zsh仍将使用哈希表,但它不会自动添加每个命令。因此,除非通过其他方式zsh将命令输入到哈希表中,否则PATH每次都会检查该命令。

如果CORRECT设置了该选项,这可能仍会导致问题。由于这确实设置了哈希表以提供拼写更正,但在PATH更改时不一定会刷新它。为了自动刷新表格,您可以使用precmd每次打印提示之前执行的钩子。

autoload -Uz add-zsh-hook
auto_rehash () {
    rehash
}
add-zsh-hook precmd auto_rehash 
Run Code Online (Sandbox Code Playgroud)


use*_*428 0

zsh 不会跳过 PATH 条目。但是,它确实优先考虑别名和 shell 函数。这不适用于您的情况,因为如果您有其中任何一个,where也会列出这一点。

在您的情况下,如果whereocamlc命令已在同一个 shell 中执行,并且按该顺序,您可以非常确定会ocamlc执行/home/choeger/ueb/uebb/amsun-integration/Runtime/test_src/../../opam/4.02.3/bin/ocamlc. 您是否尝试通过此绝对路径显式运行 Ocam?我打赌你会得到相同的输出。

顺便说一句type -a,一般来说,会提供比where.