CommandNotFoundError: Your shell has not been properly configured to use ‘conda activate’

出现问题

远程ubuntu主机安装有anaconda,ssh远程登陆,发现命令提示符行首没有conda环境名称。输入 conda activate env-name 提示shell没有配置正确,并建议使用 conda init 命令初始化shell,但使用该命令后仍然无效

但使用 source activate env-name 可行

解决方案

以下六个方法对我均有效,为什么有效见 原因 部分的分析,其中,前五种方法为临时解决方案,第六种为永久解决方案

方法一:使用 source 命令激活环境

source activate env-name

方法二:

eval "$(conda shell.bash hook)"
conda activate <env-name>

方法三:

source ~/anaconda3/etc/profile.d/conda.sh
conda activate my_env

方法四:

bash
conda activate my_env

方法五:

source ~/.bashrc
conda activate my_env

方法六(永久生效):

~/.bash_profile 中(若没有则创建)添加以下代码

# if running bash  
if [ -n "$BASH_VERSION" ]; then  
    # include .bashrc if it exists  
    if [ -f "$HOME/.bashrc" ]; then  
        . "$HOME/.bashrc"  
    fi  
fi  

原因

我出现该问题的原因是环境变量设置的问题,我也有看到说若之前没有正确退出conda环境就退出shell也可能出现该问题,见这里

出现环境变量问题的原因在于bash没有读取 ~/.bashrc 文件导致,anaconda会在安装后修改该文件,使得bash能够获得conda相关的环境变量

这是因为读取 .bashrc 文件并非登录shell所必须自动执行的步骤,得分情况,例如交互式login模式的shell,在没有指定的情况下它默认就不会读取。

上述第三到六的方法其实都在做同一件事,就是读取 conda.sh 文件(执行 .bashrc 目的也是读取该文件),配置conda环境变量

上述方法一和二源于 issue,方法二也是手动设置conda环境变量

shell变量

linux下shell变量分为自定义变量和环境变量,在交互环境中指定一个变量即为自定义变量,该变量仅对当前shell有效,而用 export 导出的变量即为环境变量,它对当前shell及其子shell生效

使用 bash 命令执行脚本会在子shell中执行,故脚本中的变量对当前shell无效

使用 source 命令执行脚本是在当前shell中执行,故可以获取到脚本中的变量

linux中的环境变量分为系统环境变量和用户环境变量

linux中默认带有的环境变量配置文件有 /etc/profile, /etc/bashrc(ubuntu下为bash.bashrc), ~/.bash_profile, ~/.bash_login, ~/.profile, ~/.bashrc

其中 /etc/ 下的就是系统级,~/ 下的就是用户级

shell分类及配置

根据是否需要登录分为登录shell和非登录shell,根据是否可交互分为交互式shell和非交互式shell,这两大类是交叉关系

模式登录非登录
交互/etc/profile, (~/.bash_profile, ~/.bash_login, /.profile 按顺序查找这三个,找到一个就停)~/.bashrc
非交互/etc/profile

看着上面配置文件一大堆,其实总结起来就两种(针对bash):profile 和 bashrc,它们都有系统级和用户级

你可以将shell比作cs架构,shell有一个后端类似与web服务器,而有很多类型的交互窗口(例如bash、zsh等,类比app、网页等)可以与后端通信。

每次当你登录shell时,你就相当于创建了shell的后端服务,它会读取profile配置文件。然后就会启动bash或zsh的交互窗口,它们就会读取各自的配置文件(bashrc、zshrc等,只有在交互式shell下才会读取,因为它的作用就是便于交互),后续如果你在已经创建的shell中创建新的bash窗口,它会继承现有shell的profile配置并且再次读取bashrc配置

故简单来说profile文件是在用户登录时执行的,而bashrc是在创建新的shell窗口执行的。

例如,当你使用 ssh user@server 或者 su -l user 登录交互式shell时(相当于创建shell后端),会先执行 /etc/profile 然后去用户的home目录下依次寻找~/.bash_profile.bash_login.profile 这三个文件,找到任意一个后就不再执行后面的文件了。登录shell时是不会执行任何bashrc文件的。(但是一般会在profile文件中判断当前shell,例如如果是bash则会自动去读取bashrc文件,毕竟你要交互还是得通过bash,但不读取也是能用的,但会少一些bash的自定义配置)

注:PS1变量控制交互式命令符前面的那个提示符,你可以将其修改为任何你想要的,例如显示时间、主机名、用户名等,具体参照这里

而当你shell中新开一个bash交互窗口或者使用 su user 切换用户时,新的bash窗口会先执行 /etc/bash.bashrc然后执行用户目录下的.bashrc文件,此时不会执行任何profile文件(但一般来说,新开一个交互窗口都是在一个已经登录上的shell中执行的,此时已经执行过profile了,所以新开的窗口也是继承了profile环境的)。

注:su user 使用的是非登录模式,若要使用登录模式(同ssh登录),则需要加上 -l 参数,由于它们读取了不同的配置文件,故它们的环境变量也是不同的。

而使用 bash -c "command"执行的命令就是“非登录非交互”的,它其实是在当前shell的基础上新开了一个bash窗口去执行命令,它只会继承当前shell的环境而不会读取任何配置文件(毕竟没有新开shell后端就不会读取profile文件,也不是交互式的就不用读取bashrc文件)

还有一种“登录非交互”模式的,例如“ssh user@server ‘command’”,因为是登录式的,需要新开启shell后端,故会读取profile文件,但是非交互的,故不会读取bashrc文件

Leave a Comment