【问题标题】:Conda activate.d and deactivate.d do not behave what I expectConda activate.d 和 deactivate.d 不符合我的预期
【发布时间】:2020-09-03 10:19:52
【问题描述】:

我正在尝试使用 activate.d 和 deactivate.d 来修改 conda 中的 $PATH 变量,例如:

在activate.d中:

export OLD_PATH = $PATH
export PATH= "/path/to/something:$PATH"

在 deactivate.d 中:

export PATH = $OLD_PATH
unset OLD_PATH

base 环境中,echo $PATH 输出:

(base) $ echo $PATH
/home/myname/anaconda3/bin:/home/myname/anaconda3/condabin:/home/myname/bin:/home/myname/.local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/cuda-8.0/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin

然后我通过以下方式激活我的环境:

(base) $ conda activate myproject

myproject 环境中,echo $PATH 输出:

(myproject) $ echo $PATH
/path/to/something:/home/myname/anaconda3/envs/myproject/bin:/home/myname/anaconda3/condabin:/home/myname/bin:/home/myname/.local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/cuda-8.0/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin

这正是我所期望的。但是,当我尝试使用

返回 base 环境时
(myproject) $ conda deactivate

我期望echo $PATH 将输出与在 base 环境中所做的相同的事情。但是,我得到的是:

(base) $ echo $PATH
/home/myname/anaconda3/envs/myproject/bin:/home/myname/anaconda3/condabin:/home/myname/bin:/home/myname/.local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/cuda-8.0/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin

注意第一个路径是/home/myname/anaconda3/envs/myproject/bin,而不是/home/myname/anaconda3/bin

那里发生了什么?

【问题讨论】:

    标签: linux anaconda conda


    【解决方案1】:

    不对称破坏了可逆性

    问题是 Conda 也在操纵 PATH 变量,并且脚本的运行顺序与正确的逆运算不一致。即activate和deactivate的操作顺序是:

    1. 更新环境变量(包括PATH
    2. etc/conda/(de)activate.d 文件夹中运行脚本。

    为了与逆运算一致,需要运算对称。也就是说,activate 应该是 (1) 然后是 (2),deactivate 应该是 (2) 然后是 (1)。

    相反,您保存的 OLD_PATH 实际上对应于 PATH 被操纵以激活 env。

    解决方法

    您无需尝试捕获OLD_PATH,而是可以仅跟踪添加的内容并在停用脚本中将其删除。例如,像

    activate.d 脚本

    export MY_ADDED_PATH="/path/to/something"
    export PATH="$MY_ADDED_PATH:$PATH"
    

    deactivate.d 脚本

    # Credit for escaping: https://unix.stackexchange.com/a/129063/148899
    escaped_lhs=$(printf '%s\n' "$MY_ADDED_PATH:" | sed 's:[][\\/.^$*]:\\&:g')
    export PATH=$(echo "$PATH" | sed "s/$escaped_lhs//") 
    unset MY_ADDED_PATH
    

    这似乎对我在 osx-64 上有效。


    调试提示

    Conda 处理起来可能很麻烦,因为它是 shell 函数和 Python 的混合体。然而,其中一件巧妙的事情是 Conda 入口点(例如,bin/conda)具有一些返回 shell 命令字符串的内部函数。

    具体来说,当运行conda activate foo 命令时,可以检查在shell 中运行的内容,使用

    $CONDA_EXE shell.posix activate foo
    

    同样,

    $CONDA_EXE shell.posix deactivate
    

    将列出停用的操作。这并不是 Conda 在激活和停用方面所做的全部,但它涵盖了大部分内容。

    【讨论】:

    • 我没有 /etc/conda 目录。至少在这个系统上是 catalina。我应该重新安装 conda 还是 anaconda?
    • @RichMeister 请注意,这不在根 /etc 文件夹中,而是在每个环境文件夹下(即 $CONDA_PREFIX)。人们经常不得不创造它。例如,在激活环境的情况下,您可以使用 mkdir -p $CONDA_PREFIX/etc/conda/{de,}activate.d 创建文件夹。
    猜你喜欢
    • 1970-01-01
    • 2013-10-18
    • 2023-03-13
    • 1970-01-01
    • 2020-03-02
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    相关资源
    最近更新 更多