出现问题
远程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文件