16

我通过自制软件安装了rbenv,现在不知道为什么path_helper 把~/.rbenv/shims 放在了路径的末尾而不是开头。最重要的是,path_helper 是如何获得这些信息的?

根据 path_helper 的手册页,它从 /etc/paths 和 /etc/paths.d 中的文件读取条目。但我在那里找不到字符串“.rbenv/shims”。

~% cat /etc/paths 
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin
~% ls -la /etc/paths.d 
total 0
drwxr-xr-x    2 root  wheel    68 Jun 21 03:16 .
drwxr-xr-x  107 root  wheel  3638 Sep 10 09:59 ..
~% /usr/libexec/path_helper
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Users/gordon/.rbenv/shims"; export PATH;
4

2 回答 2

14

我怀疑您的.bash_profileor.bashrc正在添加 到您的 PATH 中,并且在 shell 启动期间调用.rbenv/shims之前的某个时间点正在运行 。path_helper

path_helper 的手册页打开:

 The path_helper utility reads the contents of the files in the directo-
 ries /etc/paths.d and /etc/manpaths.d and appends their contents to the
 PATH and MANPATH environment variables respectively.

这里的关键点是 path_helper 实用程序旨在将内容添加到现有PATH设置,而不是替换它们。(实际上,它真正做的是预先添加内容,而不是附加它们,这对PATH变量很重要......)

因此,如果我从 my 上的条目开始PATH,由 path_helper 生成的设置将确保该条目在PATH它生成的位置上继续。

% echo $SHELL
/bin/bash
% uname
Darwin
% /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin"; export PATH;
% PATH="" /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin"; export PATH;
% PATH=foo /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo"; export PATH;

请注意,foo我的 PATH 中的最后一行已经包含在内,尽管 和 的内容/etc/paths/etc/paths.d/*没有改变。

同时,path_helper 实用程序似乎也小心不要产生具有重复条目的路径;它在连接/etc/pathsand/etc/paths.d/*和当前 PATH.

后一个细节可能特别令人困惑,因为与原始PATH设置(!)相比,它可能导致条目重新排序。

以下是此行为的一些示例: 第一种情况显示重复foo被删除。第二种和第三种情况说明了条目重新排序:在两种情况下生成的 PATH 相同,但在第三种情况下,/usr/bin条目已从中间foo移动barPATH. (这种重复条目删除似乎仅基于条目对上的简单字符串匹配,如下面的第四种情况所示,字符串/usr/bin/保持在foo/和之间bar。)

% PATH=foo:foo /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo"; export PATH;
% PATH=foo:bar /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo:bar"; export PATH;
% PATH=foo:/usr/bin:bar /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo:bar"; export PATH;
% PATH=foo/:/usr/bin/:bar /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo/:/usr/bin/:bar"; export PATH;

最后,在应得的地方给予赞扬:虽然上面的所有命令序列都是我自己调查的结果,但我最初是在阅读此处path_helper的注释后受到启发来研究的行为,其中指出重用环境变量集由父进程。path_helperPATH

于 2012-12-31T12:23:56.043 回答
11

path_helper 手册页不正确。手册页说 path_helper 将 /etc/paths.d 附加到 PATH 上。但实际上,path_helper 是从 /etc/paths 将 /etc/paths.d 附加到列表中,然后有效地将结果预置到实际预先存在的 PATH 上(以及从该列表中清除覆盖重复项的 PATH )。

确切地说,仅以 PATH 为例,它的作用是:

  1. 读取文件 /etc/paths 中的路径列表
  2. 将目录 /etc/paths.d 中文件的路径列表附加到它上面
  3. 改变 PATH 变量以删除列表中的任何项目
  4. 将变异的 PATH 变量的值追加到列表中
  5. 将此列表保存为新的 PATH

用伪代码重新表述这一点,它正在做的是:

  1. NEWPATH = 读取(/etc/paths)
  2. NEWPATH = $NEWPATH +append+ 读取(/etc/paths.d/*)
  3. PATH = $PATH -minus- $NEWPATH
  4. NEWPATH = $NEWPATH +追加+ $PATH
  5. 路径 = $NEWPATH

危险在于,如果您手动配置 PATH,可能是为了添加覆盖系统路径组件的组件。如果 path_helper 在您不期望的时候被调用,那么它将通过将系统范围的路径组件放在路径组件之前来撤消您的更改。

路径助手会如何被意外调用?例如,它由 /etc/zshenv 调用,每次启动 zsh shell 时都会调用它,无论它是子 shell,还是从另一个应用程序(如 emacs)调用的 zsh 实例,或其他什么。

我已经把它写成了关于 path_helper 的 OpenRadar 错误报告

于 2013-08-02T10:13:00.870 回答