免责声明:我不是 conda 开发人员,也不是 Bash 专家。下面的解释是基于我对代码的跟踪,希望我能理解。此外,以下所有链接都是在撰写此答案时指向主提交的永久链接 (7cb5f66)。行为/行可能会在未来的提交中发生变化。当心:前方有深兔子洞!
请注意,此解释是针对命令source activate env-name,但在 conda>=4.4 中,激活环境的推荐方法是conda activate env-name。我认为如果有人使用conda activate env-name,您应该在我们进入cli.main 函数的部分附近找到解释。
对于 conda >=4.4,CONDA_INST_DIR/bin/activate,我们发现倒数第二行和最后一行 (GitHub link):
. "$_CONDA_ROOT/etc/profile.d/conda.sh" || return $?
_conda_activate "$@"
第一行在$_CONDA_ROOT/etc/profile.d 目录中获取脚本conda.sh,该脚本定义了_conda_activate bash 函数,我们将参数$@ 传递给该函数,这基本上是我们传递给的所有参数activate 脚本。
在兔子洞的下一步,我们查看$_CONDA_ROOT/etc/profile.d/conda.sh并找到(GitHub link):
_conda_activate() {
# Some code removed...
local ask_conda
ask_conda="$(PS1="$PS1" $_CONDA_EXE shell.posix activate "$@")" || return $?
eval "$ask_conda"
_conda_hashr
}
关键是那行ask_conda=...,尤其是$_CONDA_EXE shell.posix activate "$@"。在这里,我们使用参数shell.posix、activate 运行 conda 可执行文件,然后是传递给此函数的其余参数(即,我们要激活的环境名称)。
进入兔子洞的又一步......从这里,conda 可执行文件调用cli.main function,由于第一个参数以shell. 开头,它从conda.activate 导入main 函数。此函数创建Activator 类(在同一文件中定义)和runs the execute method 的实例。
execute 方法处理参数和stores the passed environment name into an instance variable,然后确定activate command has been passed,所以它是runs the activate method。
又进了兔子洞……activate方法调用build_activate method,它调用another function来处理环境名称以找到环境前缀(即环境在哪个文件夹)。最后,build_activate method adds the prefix to the PATH 通过_add_prefix_to_path method。最后,build_activate 方法returns a dictionary 需要运行以“激活”环境的命令。
再深入一步...从build_activate 方法返回的字典被_yield_commands method 处理成shell 命令,这些命令被传递给_finalize 方法。 activate 方法返回运行 the _finalize method 的值,该值返回临时文件的名称。临时文件具有设置所有适当环境变量所需的命令。
现在,退一步说,在 activate.main 函数中,execute 方法的返回值(即临时文件的名称)是 printed to stdout。这个临时文件名被存储在 Bash 变量 ask_conda 回到 _conda_activate Bash 函数中,最后,临时文件由 eval Bash 函数执行。
呸!我希望我做对了一切。正如我所说,我不是 conda 开发人员,也不是 Bash 专家,所以请原谅我采用的任何解释捷径,但不是 100% 正确。只需发表评论,我会很乐意修复它!
我还应该注意,在 conda >=4.4 中激活环境的推荐方法是 conda activate env-name,这是造成如此复杂的原因之一 - 现在主要在 Python 中处理激活,而(我认为)以前它或多或少是直接在 Bash/CMD 中处理的。