记环境变量配置错误引发的血的教训

前言

对于自己来说这算是一次比较严重的事故,事后回顾了一下,虽然解决的问题的步骤不算特别复杂,但是如果当时电脑真的无法开机,造成的后果将是非常严重,因为自己最后一次备份代码是在半个月前,相当多的重要资料都没有备份。 这是一次血的教训,以后做事一定要仔细,尤其是修改重要的配置之前一定要仔细,而且要做好备份,切记不要盲目自信.

事件起因

下班之前,执行gradle相关命令的时候,提示版本太低,自己参照博客ubuntu 16.10安装Gradle-5.0 下载了4.4 版本的gradle,然后解压到并复制到/opt/gradle目录中,参照博客linux 下配置gradle 环境变量配置了环境变量. 该篇博客中的环境变量介绍的是是按照下边的代码格式进行配置的.

1
2
export GRADLE_HOME=/usr/local/gradle-2.2.1
export PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin:${GRADLE_HOME}/bin:${JAVA_HOME}:${PATH}

但是自己配置的时候 没有加后边的PATH

1
2
export GRADLE_HOME=/opt/gradle/gradle-4.4
export PATH=${GRADLE_HOME}/bin // 就是这行代码后边少写了 $PATH

自己将环境变量添加到当前用户根目录中的 .bashrc 文件中, 在当前目录中执行命令source .bashrc使配置立即生效.

然后执行 gradle -v 命令, 发现仍然是旧版本,新版本并没有生效.

自己尝试将同样的代码复制到当前用户的.profile文件,执行命令source .profile.配置依然没有生效.

接下来就开始坑爹了, 自己将错误的配置复制到/etc/profile文件中. 执行命令 source profile , 还是没有生效。这时,自己怀疑是不是需要重启电脑才可以。

重启电脑后,悲剧就发生了, 无论是普通用户还是root用户, 输入账号和密码后,屏幕闪烁一下,提示再次输入密码, 也就是不断循环登录.

自始至终,自己都没有怀疑是配置错误的问题,一直瞎试。如果自己真的熟悉各个配置文件的作用和环境变量的格式, 或者说自己确定source命令的用法,就不会去重启电脑,自然不会酿成电脑无法登陆的悲剧.对编程而言, 有些知识点似懂非懂真的是很要命的.

解决过程

当时自己就想这下算是凉凉了, 所有的代码都在电脑里边,最近的一次备份还是半个月前, 硬盘中还有大学以来所有的照片和其它重要的资料。后来上网查了一下, 发现ubuntu循环登录的问题许多人都曾遇到过,自己仿佛看到了希望.毕竟之前有那么多人都遇到了这个问题,自己也不是第一个吃螃蟹的人,所以也就不用害怕了. 然后就开始参照各个博客中的方法进行尝试.

百度输入如下关键字 ubuntu 正确密码 循环登录 ,可以搜索到许多的博客, 主要分三种情况:

  1. .Xauthority 权限问题,参照博客ubuntu密码正确,一直无法进入桌面系统,又跳回到登录界面
  2. 错误的修改了环境变量文件导致无法登录, 参照博客ubuntu16.04开机循环输入密码无法进入桌面的解决办法
  3. NVIDIA驱动问题, 参照博客Ubuntu 循环登录 解决办法

不同文章的作者都根据自己的情况都成功解决了循环登录的问题,很显然自己属于第二种情况导致的。

按照博客二中方法, ctrl alt f1 进入命令行模式,输入账户名(自己电脑的root账户账户名为 root)和密码, 登录后发现除了cd 命令之外的其它命令统统都不管用, 自己输入 ls 命令 或者 sudo vim 命令时都出现了乱码. 有的博客中说是因为中文乱码造成的,需要安装软件来修改语言配置,但是无论自己执行什么命令都出现乱码,根本就无法修改/etc/profile文件.有关语言的配置文件自然也无法修改. 静下心仔细想想, 命令 ls都无法使用, 该命令主要是列出当前目录中的文件或者目录列表, 不应该与语言配置文件有关,所以乱码应该不是因为语言配置的问题. 后来, 搞了三个小时都没有搞定, 查了许多博客,问了自己同学,最终还是没有找到解决办法.

外边下着大雨,先背上电脑下班回家再说,回去了再慢慢解决。一路上心神不定,毕竟事关重大,自己也不能怠慢,后来坐在地铁中决定用谷歌浏览器搜搜有没有其它解决方案. 这时自己也换了一种搜索方式, 将搜索关键字改为:linux 修改profile 无法登陆 。 后来看到这样一篇博客: Ubuntu Linux解决:修改profile文件无法进入Ubuntu的方法 (最终也是参照这篇博客解决了我的问题) 。期间换乘地铁的时候,就忍不住着想试试,后来实在没地方就放弃了. 回到所住的城中村时已经晚上九点多了,大雨丝毫没有停歇的意思, 在楼下的拉面馆吃饭的时候, 自己迫不及待的拿出电脑, 按照博客中的方法试了一下, 果然不出所料, 不到五分钟问题迎刃而解,把自己激动的不要不要的.

解决过程记录如下:

  • 1.ctrl alt f1 进入命令行界面,登陆root账号

  • 2.输入命令 cd /etc进入etc文件夹

  • 3.执行如下命令进入profile文件的文本编辑模式

    1
    /usr/bin/sudo vi profile
  • 4.删除掉错误的配置,然后重启,编辑工具vi的具体操作可以参考vi(vim)的常用操作
    此处用到vi的操作如下

    1
    2
    3
    4
    进入编辑模式 按按键 i
    删除操作 x 一个字符  dd 删除一行
    shift + : 也就是按下shift和冒号进入尾行命令模式
    wq 保存并推出

执行完上边三步之后,重启电脑就可以登录到桌面了,但是此时打开命令好执行命令会报 由于/bin 不在PATH 环境变量中,故无法找到该命令的错误,参考博客:在ubuntu系统中,遇到 “由于/bin 不在PATH 环境变量中,故无法找到该命令”问题/etc/profile 文件的最下方添加如下代码,并执行命令source /etc/profile使配置立即生效。

1
export PATH=$PATH:/sbin:/usr/bin:/usr/sbin

彻底搞懂环境变量的配置

为什么会出现上边的情况呢,主要还是自己没有彻底弄明白环境变量如何配置.在半懂不懂的情况下配置了错误的信息,而且一错再错。

那么究竟环境变量应该怎么配呢?只有彻底弄清楚了配置的方法,才可以避免下次出现同样的问题.

这里需要弄清三个问题:

  1. linux中各个环境变量配置文件的具体作用
  2. 环境变量的格式 及配置方法
  3. 如何是配置立即生效

linux 环境变量介绍

在linux系统中,环境变量按照作用的范围不同分为系统环境变量和用户环境变量。

系统环境变量: 每一个登录用户都使用该级别的环境变量。

用户环境变量: 每一个登录的用户只能够读取到属于自己的用户级环境变量。

提示: 在linux中使用source命令可以使配置立即生效。
例如:如果修改了 /etc/profile文件,那么只需要在该文件所在的目录中执行命令 source profile ,如果修改了当前用户根目录中的 .bashrc只需要在当前文件所在的目录中执行source .bashrc中即可使配置立即生效。

1. 系统级环境变量

/etc/profile文件
在系统启动后第一个用户登录时运行,并从/etc/profile.d目录的配置文件中搜集shell的设置,使用该文件配置的环境变量将作用于登录到系统的每一个用户。

/etc/bashrc(Ubuntu和Debian中是/etc/bash.bashrc)文件
在 bash shell(bash 是shell的一种)打开的时候,该文件中的环境变量会生效。
bash和shell是什么可以参考这篇文章:什么是shell和bash?

shell 有不同的类别,不同类别所使用环境变量配置文件也不同。一般情况下,非登录shell不会执行任何profile文件,非交互shell模式不会执行任何bashrc文件。
为什么登录shell会执行profile文件呢,因为系统环境变量会对每个用户都生效,那么当使用 ssh命令,或者su -命令的时候相当与登录一个新的用户,必然会执行 /etc/profile文件使系统及的环境变量生效。

1
2
3
4
5
6
7
# 登录shell和非登陆shell:
登录shell # 需要输入用户密码,例如 ssh 登录或者 su - 命令提权都会启动login shell模式
非登陆shell # 无需输入用户密码;

# 交互shell和非交互shell:
交互shell # 提供命令提示符等待用户输入命令的是交互shell模式
非交互shell # 直接运行脚本文件是非交互shell模式

2.用户级环境变量

~/.profile (推荐首选)
/.profile表示当前用户根目录中的 .profile文件。当用户登录时执行,每个用户都可以使用该文件来配置专属于自己的环境变量。

~/.bashrc
当用户登录时以及每次打开新的shell时该文件都将被读取,不推荐在这里配置用户专用的环境变量,因为每开一个shell,该文件都会被读取一次,效率肯定受影响。

一般情况下,Linux加载环境变量配置文件的执行顺序为

1
2
3
4
5
==> /etc/profile
==> ~/.bash_profile | ~/.bash_login | ~/.profile
==> ~/.bashrc
==> /etc/bashrc
==> ~/.bash_logout

更为详细的介绍可以参照博客:Linux环境变量文件介绍

环境变量的格式和配置

例如 java环境变量配置的格式如下:

1
2
3
# java环境变量
export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-amd64
export PATH=$JAVA_HOME/:$PATH

如果配置多个环境变量,可以参照下边这样配置:

1
2
3
# gradle环境变量
export GRADLE_HOME=/usr/local/gradle-2.2.1
export PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin:${GRADLE_HOME}/bin:${JAVA_HOME}:${PATH}

从上边可以看到: 环境变量是将多个${JAVA_HOME}/bin 格式的路径 用:连接起来,而且要以 ${PATH}结尾, JAVA_HOME 表示的是一个路径,如果多个路径怕配置错了那就老老实实一个一个配置。

可以总结出环境变量的正确格式应该如下

1
PATH=$PATH:<PATH 1>:<PATH 2>:<PATH 3>:------:<PATH N>

配置gradle环境变量

这里以配置gradle环境为例学习环境变量的配置。

参照博客ubuntu 16.10安装Gradle-5.0安装了gradle 4.4。
gradle的安装目录为/opt/gradle/gradle-4.4, 在当该前用户的家目录的 .bashrc文件中添加以下代码

1
2
export GRADLE_HOME=/opt/gradle/gradle-4.4
export PATH=${GRADLE_HOME}/bin:$PATH

然后执行代下方命令使配置立即生效。

1
source .bashrc

执行 gradle -v 可以看到环境变量已经生效,也可以执行echo $PATH 查看环境变量

此时执行echo $PATH输出如下结果

1
/home/shaoyance/.pyenv/shims:/home/shaoyance/.pyenv/bin:/home/shaoyance/bin:/home/shaoyance/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/opt/node-v8.9.4-linux-x64/bin

为什么没有刚才配置的gradle环境变量呢? 实际上环境变量已经生效,执行 gradle -v可以看到。 但是命令echo $PATH不能将最新的环境变量打印出来。重启之后再输入命令echo $PATH,会输出如下结果

1
/opt/gradle/gradle-4.4/bin:/home/shaoyance/.pyenv/shims:/home/shaoyance/.pyenv/bin:/home/shaoyance/bin:/home/shaoyance/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/usr/bin:/usr/sbin:/opt/node-v8.9.4-linux-x64/bin

上边显示的结果是当前用户下的所有环境变量,不同的环境变量是以冒号(:)分割开的,可以看到配置的gradle 环境变量/opt/gradle/gradle-4.4/bin 已经出现在环境变量中了。

事后总结

通过这件事,可以汲取以下下几点教训:

  1. 重要代码要及时备份
  2. 最好不要动root用户下的代码,尤其是一些重要的配置文件,即便是要动,也一定要先做好备份,修改的时候一定要仔细仔细再仔细.
  3. 出了问题一定不要慌张, 只要不是硬件的问题, 总是有解决的办法.一定要冷静,查阅资料的时候首选谷歌,然后百度.

参考博客:

环境变量文件介绍
Linux下查看和添加环境变量