pip在使用sudo时不遵循PIP_INDEX_URL

9 投票
2 回答
17336 浏览
提问于 2025-04-18 09:15

根据文档,我可以让pip使用我自己的私有pypi仓库,而不是官方的那个:

For pip this can be done by setting the environment variable PIP_INDEX_URL in your .bashrc/.profile/.zshrc:
export PIP_INDEX_URL=http://localhost:8080/simple/

所以我在我的Debian服务器上,把我的私有仓库(比如说 http://pypi.mycompany.com/simple)添加到了 /etc/profile 文件里。但是pip还是报错:

john@server:~$ sudo pip install ipython
Downloading ...
    Cannot fetch index base URL https://pypi.python.org/simple/
    ...

看起来pip没有识别我设置的环境变量 PIP_INDEX_URL。这是为什么呢?

更新:

按照@Ivo的指示,我发现我的Python根本没有看到这个变量:

john@server:~$ sudo python -c "import os; print(os.getenv('PIP_INDEX_URL'))"
None

2 个回答

4

Sudo会通过重置大部分环境变量来清理安全环境。默认情况下,它会重置所有不在保留列表中的变量。Sudo有三类环境变量:检查、重置和保留。默认情况下,它会重置所有不在保留列表中的变量。

可用选项:

  1. 如前所述,你可以通过 -E--preserve-env 全局传递所有环境变量。

    这会带来安全问题。传递环境变量可能会污染或影响在(安全)环境中的执行。比如 $LD_PRELOAD$IFS 的问题。

  2. -E--preserve-env 支持一个变量列表作为参数,以保留除了默认变量之外的其他变量:

    sudo --preserve-env=PIP_INDEX_URL pip install python
    
  3. 你可以通过命令行将环境变量显式传递给 ssh 命令:

    sudo -e PIP_INDEX_URL=${PIP_INDEX_URL} pip install ipython
    

    ${PIP_INDEX_URL} 会在传递给 sudo 之前被命令行解析。

    这是一个实用的命令行技巧,适用于 ssh 以及其他需要直接将参数和环境传递给子进程的情况。

  4. sudoers 配置文件中修改你的 sudo 配置,以扩展允许传递给子进程的环境变量列表。可以查看 env_keep 选项。

    DEFAULT env_keep+=PIP_INDEX_URL
    

    我认为这个选项是最干净的,特别是在多个用户需要使用相同 pip 选项的系统上。

    你的 sudoers 文件的最后一行可能包含一个 #includedir 指令。如果有的话,可以把你的修改放在那个目录下的文件中,比如 /etc/sudoers.d/pip_environment,并为 PIP_INDEX_URLPIP_TRUSTED_HOSTPIP_EXTRA_INDEX_URL 和其他配置所需的选项添加保留选项。

参考资料:

  • sudoers 配置: man 5 sudoers

  • sudo 选项: man 8 sudo

  • Linux 和 Unix 的安全编程指南

  • pip 环境变量的命名格式为 PIP_ 后面跟着完整命令行标志的大写拼写。请参见: pip 配置文件文档

  • 你可以通过以 root 身份运行 sudo -V 来查看检查、重置和保留列表:

    % sudo sudo -V
    
    # ...
    Environment variables to check for sanity:
            TZ
            TERM
    # ...
    Environment variables to remove:
            *=()*
    # ...
    Environment variables to preserve:
            MAIL
            HOME
    
10

找到了。其实很简单:出于安全考虑,sudo 默认情况下不会使用环境变量。要让 sudo 保留环境变量,可以使用 -E 这个选项,比如:

sudo -E pip install ipython

撰写回答