【问题标题】:Why does zsh ignore the PATH entry order?为什么 zsh 会忽略 PATH 入口顺序?
【发布时间】:2016-08-01 07:41:54
【问题描述】:

我在这里尝试使用一个非常基本的设置模式:我有两个不同的给定工具安装(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

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

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

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

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

那么为什么 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

编辑2: 这是 setopt 的输出:

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

Config 是找到的 grml 配置 here 加上 .local 文件中的一些路径变量。

【问题讨论】:

    标签: shell path command zsh resolution


    【解决方案1】:

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

    rehash
    

    hash -r
    

    这应该会在您每次更改 PATH 时自动发生,它的主要用途是,当新的可执行文件被添加到已经在 PATH 中的目录时。


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

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

    setopt nohashcmds
    

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

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

    autoload -Uz add-zsh-hook
    auto_rehash () {
        rehash
    }
    add-zsh-hook precmd auto_rehash 
    

    【讨论】:

    • 这是一个很好的答案。事实上hash 表明该条目仍然指向旧位置。不幸的是,重新散列在这里并没有改变任何事情。 rehash 从哪里获得它的来源?我在这里遇到了真正的错误吗?
    • 它应该从PATH获取它的信息。奇怪……你用的是什么版本的zsh
    • zsh 5.1.1 (x86_64-redhat-linux-gnu)
    • 所以,我做了更多测试,似乎PATH 中的任何更改都应该自动导致根据新的PATH 使用正确的二进制文件,至少在zsh 上的默认设置是5.0.6 和 5.2。所以这是一个错误似乎不太可能。能否请发布您的配置链接或至少将setopt 的输出添加到您的问题中?
    • 添加了 setopt 并链接到配置文件。
    【解决方案2】:

    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 提供更详细的信息。

    【讨论】:

    • 一定有不同的原因。从理论上讲,ocamlc 可以查询它是如何被调用的(通过 PATH 或通过 abs 路径),尽管很少有程序这样做。尝试显式减少 PATH,即PATH=/home/choeger/ueb/uebb/amsun-integration/tests/pendulum/../../opam/4.02.3/bin ocamlc -v .... 在这种情况下,zsh 没有任何其他 PATH 可供选择。如果你想确定,写command ocamlc 而不是ocamlc。关键字command 将绕过别名扩展和shell 函数定义。
    • 命令不会改变任何东西,明确限制路径会导致预期的结果。
    • type -awhere 的区别主要在于格式化。例外是函数,where 实际上打印函数体,而type -a 只是声明“是一个 shell 函数”。所以type -a 会提供不太详细的信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    相关资源
    最近更新 更多