Conda activate.d 和 deactivate.d 不符合我的预期
Conda activate.d and deactivate.d do not behave what I expect
我正在尝试使用 activate.d 和 deactivate.d 修改我在 conda 中的 $PATH 变量,例如:
在activate.d中:
export OLD_PATH = $PATH
export PATH= "/path/to/something:$PATH"
在德activate.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
。
那里发生了什么事?
不对称破坏可逆性
问题是 Conda 也在操纵 PATH
变量并且脚本的顺序 运行 与正确的逆运算不一致。即activate和deactivate的操作顺序都是:
- 更新环境变量(包括
PATH
)
- 运行 个脚本在
etc/conda/(de)activate.d
个文件夹中。
为了与逆运算一致,需要运算对称。也就是说,activate 应该做 (1) 然后 (2),deactivate 应该做 (2) 然后 (1)。
相反,您保存的 OLD_PATH
实际上对应于 在 PATH
被操纵以激活环境后
解决方法
您可以不尝试捕获 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
)有一些内部函数,return 串 shell 命令。
具体来说,当 运行 执行命令 conda activate foo
时,可以检查 shell 中的 运行 是什么,使用
$CONDA_EXE shell.posix activate foo
同样,
$CONDA_EXE shell.posix deactivate
将列出停用操作。这并不是 Conda 在激活和停用方面所做的全部,但它涵盖了大部分内容。
我正在尝试使用 activate.d 和 deactivate.d 修改我在 conda 中的 $PATH 变量,例如:
在activate.d中:
export OLD_PATH = $PATH
export PATH= "/path/to/something:$PATH"
在德activate.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
。
那里发生了什么事?
不对称破坏可逆性
问题是 Conda 也在操纵 PATH
变量并且脚本的顺序 运行 与正确的逆运算不一致。即activate和deactivate的操作顺序都是:
- 更新环境变量(包括
PATH
) - 运行 个脚本在
etc/conda/(de)activate.d
个文件夹中。
为了与逆运算一致,需要运算对称。也就是说,activate 应该做 (1) 然后 (2),deactivate 应该做 (2) 然后 (1)。
相反,您保存的 OLD_PATH
实际上对应于 在 PATH
被操纵以激活环境后
解决方法
您可以不尝试捕获 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
)有一些内部函数,return 串 shell 命令。
具体来说,当 运行 执行命令 conda activate foo
时,可以检查 shell 中的 运行 是什么,使用
$CONDA_EXE shell.posix activate foo
同样,
$CONDA_EXE shell.posix deactivate
将列出停用操作。这并不是 Conda 在激活和停用方面所做的全部,但它涵盖了大部分内容。