关于linux中使用source /etc/profile重新读取配置后,新的环境变量只能在当前终端里面有效,新开的终端提示 command not found

问题

在使用linux桌面环境(通常是ubuntu/debian/deepin等版本的linux)的时候,新增环境变量后,会使用source /etc/profile命令使新的环境变量立刻生效而不用重新启动系统。但经常会遇到使用source /etc/profile命令之后,新的环境变量只能在当前终端里面有效,而在新打开的终端中,使用新的环境变量就找不到了。

先通过操作来复现一下这个过程,我使用的linux分支是deepin(其他版本的类似),通过图形界面打开终端操作进入,准备添加一个新的变量testEnv

# 查看系统中,是否已经存在名字为 testEnv 的环境变量,如果输出为空,表示环境变量不存在
echo $testEnv
# 环境变量不存在,就添加 testEnv 到环境变量
sudo bash -c "echo testEnv=888888 >> /etc/profile"
# 输出/etc/profile最后一行,查看是否添加成功
tail -1 /etc/profile
# testEnv=888888
# 使 testEnv 环境变量生效
source /etc/profile
# 查看环境变量 testEnv 的值,如果输出 888888 ,表示环境变量创建成功
echo $testEnv
# 888888

新建一个终端窗口,看下是否可以输出环境变量testEnv的值。

# 输出结果为空
echo $testEnv

但是,只要重启系统,一切就正常了。

问题在于为什么?

知识点

我们知道,linux中环境变量是通过配置文件添加的,在系统启动的时候,通过加载不同的配置文件来初始化环境变量,所以环境变量找不到的问题,归根结底是配置文件的加载问题。搞清楚linux中配置文件的加载顺序,上面遇到的问题也就不难理解了。

shell是用户与Linux系统进行交互的媒介,它在运行时具有两种属性,即“交互”与“登陆”,由此衍生出交互式登录非交互式登录两种模式。

  • 交互式登录shell进程是指直接通过某终端输入账号密码后登录打开的shell进程,如使用ssh或者堡垒机进行远程主机连接,或者使用 su - username 或者 su -l username 执行的登录用户切换等。

  • 非交互式登录shell进程:图形界面下打开的终端、su username 执行的登录切换、直接运行脚本或者bash -c执行一段命令的时候。

linux 中常见的配置文件有/etc/profile~/.bash_profile~/.bashrc/etc/bashrc/etc/profile.d/*

  • /etc/profile:此文件为系统的每个用户设置环境信息,系统中每个用户登录时都要执行这个脚本,如果系统管理员希望某个设置对所有用户都生效,可以写在这个脚本里,该文件也会从/etc/profile.d目录中的配置文件中搜集shell的设置。
  • ~/.bash_profile:每个用户都可使用该文件设置专用于自己的shell信息,当用户登录时,该文件仅执行一次。默认情况下,他设置一些环境变量,执行用户的.bashrc文件。
  • ~/.bashrc:该文件包含专用于自己的shell信息,当登录时以及每次打开新shell时,该文件被读取。
  • /etc/bashrc:为每一个运行bash shell的用户执行此文件,当bash shell被打开时,该文件被读取。

关于配置文件加载顺序的说法,网上有很多,看起来也不尽相同,其实主要区别在与不同的linux发行版,包含的配置文件也是有很大区别的,即使有名字相同的配置文件,配置文件里面的内容也是大相径庭。但是基本上所有的linux发行版都会包括/etc/profile(登录后读取的第一个配置文件)和~/.bashrc两个配置文件。

对于交互式登录shell来说,一定会读取的配置文件的顺序是/etc/profile --> ~/bashrc

对于非交互式登录shell来说,一定会读取的配置文件属性是~/.bashrc,如果~/.bash_profile 存在的话,顺序是这样的~/.bash_profile --> ~/.bashrc

对于其他的各种常见配置文件的读取,以及是读取,主要取决于/etc/profile 或者 ~/bashrc 里面的具体内容,比如在centos7/etc/profile中有如下一段代码,是用来载入/etc/profile.d/*.sh配置文件的。

for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then 
            . "$i"
        else
            . "$i" >/dev/null
        fi
    fi
done

deepin系统中的.bashrc里面有一段代码,用来读取命令别名声明文件。

# Get the aliases and functions

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

所以,系统配置文件的读取顺序,需要根据系统版本的不同去了解读取顺序。

每次在配置文件中配置的新环境变量,只会对随后新启动的shell进程生效,如果想让配置文件立即生效,需要让shell进程重读配置文件,这就需要进行类似source /etc/profile 或者 . /etc/profile 这样的操作。

问题分析及解决

一般遇到本文开头说到的问题的同学,都是在图形界面下使用终端的配置的环境变量,然后通过source /etc/profile 重新读取配置文件,然后打开一个新的终端的时候,使用命令就是出现comand not found的问题。

结合上面的知识点看下,在图形界面下使用的终端属于非交互式登录的shell,以我使用的deepin系统为例,新开一个终端时,读取的配置文件应该是~/.bashrc。而新增的环境变量配置在/etc/profile,所以出现在新开终端找不到环境变量的问题。

解决办法:

  1. 在新开终端,执行source /etc/profile比较麻烦
  2. 将环境变量配置在,~/.bashrc 中,可以解决
  3. ~/.bashrc中添加source /etc/profile,这样就可以为每一个新开的终端重新读取一次/etc/profile配置文集,可以解决,多次读取/etc/profile没有发现有什么副作用。

补充

网上早期很多关于javanode等的环境变量配置的文章,感觉都是针对搭建centos服务器或者测试机的,他们之所以没有这个问题,是因为服务器基本都是通过ssh远程登录,是交互式登录模式的,每次打开一个新的远程连接,都会重新读取/etc/profile,所以不会有command not found的问题。而个人用的电脑,基本都是图形界面直接操作,所以会遇到比较多的这种问题。

<完>

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值