> 文章列表 > 【Linux】环境变量

【Linux】环境变量

【Linux】环境变量

目录

  • 背景
  • 1.概念
  • 2.常见环境变量
    • 2.1 PATH
      • 指令和自定义程序
      • 向环境变量PATH中添加路径
      • 删除PATH中的路径
    • 2.2 env:显示所有环境变量
    • 2.3 环境变量相关的命令
  • 3.通过代码获取环境变量
    • 1.char* envp[]
    • 2.第三方变量enciron
    • 3.getenv函数获取指定环境变量
    • 4.利用获取的环境变量
      • 自制pwd
      • 限制文件执行对象
  • 4.环境变量来自哪里
    • .bash_profile
    • .bashrc
    • /etc/bashrc
  • 5.环境变量的全局性
    • 全局性
  • 6.环境变量总结
  • 7.main函数的前两个参数

背景

大家在学习Java或Pathon亦或安装某个软件时,大多经历过要修改环境变量的情况,那环境变量是什么?下面让我们一起来揭开环境变量 的神秘面纱。

1.概念

  • 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
  • 当我们在编写C/C++代码时,在链接时,我们从来不知道所链接的动态库在哪,但是照样可以链接成,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
  • 环境变量通常具有某些特殊的用途,还有在系统当中通常具有全局特性。

2.常见环境变量

  • PATH:指定命令的搜索路径
  • HOME:指定用户的主工作目录(即用户登录到Linux系统中时,默认的目录)
  • SHELL:当前Shell,它的值通常是/bin/bash
  • USER:存放当前用户的用户名

通常我们使用echo $NAME来查看对应的环境变量内容(NAME:环境变量名)

在这里插入图片描述

  • PATH中各路径使用冒号 : 分隔

2.1 PATH

首先,我们创建test.c 文件,编写如下代码

在这里插入图片描述

其次,创建makefile 文件,编写如下代码

在这里插入图片描述

当我们完成相应的操作,使用make指令创建对应的可执行文件myprocess ,当我们想要执行这个可执行文件需要使用./myprocess,那我们可不可以直接使用myprcess来执行呢?答案当然是不行,那要则没做才能办到呢?这就和环境变量有关了。

指令和自定义程序

在Linux中,我们使用指令(如:ls)来操作系统,而指令也是使用C写的,放在系统的某个位置,和我们写的程序是没有区别的,这里我们使用file指令来查看lsmyprocess的区别

在这里插入图片描述

我们从上图可以看到,指令和我们写的程序是没有区别的,这些指令就是一个个已经写好的可执行文件。

我们通常想要执行一个可执行文件需要使用绝对路径或相对路径来定位需要执行文件的位置

  • 相对路径:./ ,其中.表示当前路径,/为路径分隔符
  • 绝对路径: home/../../可执行文件

所以,想要执行一个可执行文件,就需定位它的路径,而我们使用的指令之所以不用带路径就能执行,是因为它被纳入到基本指令的范畴,路径已经实现被放到了环境变量PATH,如下图

在这里插入图片描述

每当我们使用指令完成某个操作,系统就会从左向右,找到环境变量中对应的路径,执行该指令的可执行文件。

了解了这些,我们就有两个方法使得我们的可执行文件,不使用路径直接运行。

  1. 将可执行文件放入已经在环境变量中的某个路径下(会有权限限制,需在root用户下执行或sudo提权)
  2. 将可执行文件对应的路径添加到PATH 环境变量中

这里我们只讲第二种方法。

向环境变量PATH中添加路径

使用下面的指令来完成路径的添加:

export PATH=$PATH:对应的路径
  • 其中,是将$PATH:对应的路径赋值给PAT,新的值会覆盖原有的值,$PATH代表PATH中的原路径,使用 : 分割,之后是添加的新路径

如下图,向PATH环境变量 中添加myprocess 可执行文件的对应路径,之后查看PATH是否修改

在这里插入图片描述

此时我们就在该目录下创建的可执行文件,即可只使用文件名运行了

在这里插入图片描述

删除PATH中的路径

下面的指令表示为PATH重新赋值,将之前的值覆盖

export PATH=对应的路径

比方说,PATH中的路径如下:

路径1:路径2:路径3:路径4

我们想要删除路径4 ,只需复制路径1:路径2:路径3,之后复制给PATH即可

export PATH=路径1:路径2:路径3

我们使用该方法删除上面添加的路径,如下图

在这里插入图片描述

注意:

若使用export PATH=..时使用错误,覆盖了原来的所有路径,重启终端(关闭shell,重新启动)即可。

也就是说,我们进行PATH的配置只在本次登录有效,当重启后,我们添加的路径就会消失,变为原本系统默认的路径。如果想要可执行文件永久使用文件名运行,需要将其移至永久有效的路径下,相同的删除也只能删除路径下对应的文件。(拷贝和删除文件时有权限限制)

2.2 env:显示所有环境变量

我们可以使用env指令,显示所有的环境变量,如下:

在这里插入图片描述

其中:

  1. HOSTNAME:表示这台机器的主机名

    在这里插入图片描述

  2. HISTSIZE:表示保留之前指令的最大数量

    我们想要看到命令行中输入的历史命令可以使用history指令,但操作系统不会将我们所写的指令都保存下来,只会保留最新的HISTSIZE个历史指令

  3. SSH_CLIENT:表示当前是那台主机在登录我们的Luinux机器

  4. USER:当前登录用户

    我们创建一个文件或是目录,创建后它的所属组和拥有者都是根据USER来给定的

    在这里插入图片描述

    • 使用su指令切换用户,USER不会发生改变
    • 使用su -指令切换用户,USER会发生改变
  5. LS_COLOR:配色方案

    当我们使用某些指令时,会发现一些数据的颜色区别于其它数据,这就是由LS_COLOR指定的

    在这里插入图片描述

  6. PWD:确认当前用户所在的路径

    我们使用pwd指令获取当前所在位置时,使用的就是这个环境变量

    在这里插入图片描述

  7. HOME:表示当前用户所在的家目录

    不同的用户,HOME值不同

  8. LOGNAME:表示登录的用户

    • 使用su指令切换用户,LOGNAME不会发生改变
    • 使用su -指令切换用户,LOGNAME会发生改变
  • 环境变量是根据特定的人在特定的场景中使用的

2.3 环境变量相关的命令

  1. echo: 显示某个环境变量值(在环境变量名前加$符)
  2. export: 设置一个新的环境变量
  3. env: 显示所有环境变量
  4. unset: 清除环境变量
  5. set: 显示本地定义的shell变量和环境变量

3.通过代码获取环境变量

C/C++代码,main函数是程序的入口,,main函数可以接收参数,最多可以接收三个或是两个参数,写法如下:

int main(int argc,char* argv[],char* envp[])
{}
  • 编译器在编译时会自动传递这三个参数,只是我们不用而已
  • 其中,也可以只接收前两个参数,最后一个不写,我们这里先来讲最后一个参数char* enpv[],知道这个剩下两个就好理解了。
  • 我们的进程内部本身就有环境变量,这需要我们去获取(下面就是获取方式)

1.char* envp[]

envp为指针数组,main函数的第三个参数,存放指针,指针对应的数据为环境变量(执行一个额一’\\0’结尾的环境字符串),第一个无效内容指向NULL

在这里插入图片描述

这里我们要区分两个概念:

  1. 指针:表示地址,凡是具有指向能力的数据都叫指针
  2. 指针变量:表示变量,在内存中开辟空间,具有存储和被修改的能力

envp指针数组存放的是指针,指针的类型为char,指向字符串或字符,这里的envp是指向字符串,也就是环境变量。

我们将test.c 文件修改如下:

在这里插入图片描述

其中,当envp[i]为NULL时表示有效数据已经循环完毕

将makefile文件修改如下:

在这里插入图片描述

使用make指令生成可执行文件,之后运行,得出下面的结果

在这里插入图片描述

输出的正是环境变量,我们可以通过该方法在我们自己写的程序内获取环境变量。

2.第三方变量enciron

除了main函数的第三个参数,我们还可以使用libc中定义的全局变量environ 指向环境变量表,来获取环境变量。

在这里插入图片描述

注意:

  1. environ没有包含在如何头文件内,在使用时要用extern声明,表示为外部变量。
  2. environ为二级指针,相当于指针数组指向环境变量表

test.c 修改如下:

在这里插入图片描述

使用make指令生成对应的可执行文件,之后执行该文件,获得如下结果

在这里插入图片描述

我们依然可以看到,使用该方法就可以获得环境变量。

问题:

我们已经知道可以通过main函数的第三个参数或二级指针environ变量获取环境变量,然后呢?难道我们要用的时候只能通过遍历环境变量表来获取想要的环境变量吗?这是不是太麻烦了?

这样做在我们想要获取某一环境变量时却是i不方便,所以,我们在实际操作中最常用的是下面要讲的函数获取环境变量,想要什么环境变量直接告诉函数,通过它来获取。

3.getenv函数获取指定环境变量

通过向getenv函数传递想要获得的环境变量的环境变量名来获取,该函数头文件为**<stdlib.h>**

格式:

char* 变量名 = getenv("环境变量名");

我们通过下面的代码来演示,获取USER的环境变量,其它的环境变量也是一样的

首先,将test.c 文件修改如下:

在这里插入图片描述

使用make指令生成可执行文件,执行该文件获取如下结果:

在这里插入图片描述

  • 想要获取其它的环境变量也是使用相同的方法

4.利用获取的环境变量

现在我们既然可以获取到环境变量了,那我们该用它来做什么呢?下面通过两个例子来向大家介绍一二

自制pwd

我们可以自己写一个程序,来获取当前所处的位置,如下:

首先,再次将test.c 文件修改如下:

在这里插入图片描述

使用make指令生成可执行文件后执行它,获取如下结果:

在这里插入图片描述

我们还可以将该可执行文件的路径放在PATH环境变量下,在为其改名为mypwd ,这样我们在如何地方都可以执行它,如下:

在这里插入图片描述

限制文件执行对象

若一个可执行文件,我们只想要让自己或其它指定用户使用,我们可以依靠环境变量做出限制

首先,再次将test.c 文件修改如下:

在这里插入图片描述

注意:该程序用到strcmp函数,该函数需要引用string.h

其次,使用make指令生成可执行文件,在两个用户下执行该文件,查看结果

用户YX

在这里插入图片描述

root用户

  • 注意:这里要使用su -来切换到root用户的家目录,在到可执行文件的目录下运行该文件,才可以看到效果。否则对应的USER环境变量不会改变

在这里插入图片描述

4.环境变量来自哪里

环境变量是我们登录LInux系统后,在对应用户的家目录 下的.bash_profile.bashrc两个配置文件中获取的

在这里插入图片描述

.bash_profile

打开.bash_profile文件查看其内容

在这里插入图片描述

在我们登录成功后,系统会调用该配置文件,执行其内容,调用.bashrc配置文件,加载配置文件PATH环境变量得以添加。

.bashrc

在打开.bashrc文件查看其内容

在这里插入图片描述

/etc/bashrc

在这里插入图片描述

  • 存放全局的环境变量

总结:

登录系统后,系统会调用对应用户家目录下的.bash_profile配置文件,.bash_profile配置文件中又调用同目录下.bashrc配置文件,而.bashrc配置文件又调用/etc/bashrc配置文件,生成环境变量。

5.环境变量的全局性

环境变量本质就是一个内存级的一张表,这张表由用户在登录系统时,进行给特定用户形成属于自己的环境变量表。而环境变量通常具有全局属性,可以被子进程继承下去。

我们先来看一下下面的两种情况:

情况1:

我们在命令行中编写一个变量,并为它赋值,之后使用echo指令取出

在这里插入图片描述

情况2:

在命令行编写变量并为它赋值时使用export指令修饰,使其变为环境变量,之后使用env指令查看

在这里插入图片描述

大家或许都知道这两种现象的存在,但对于它为什么存在却知之甚少,原因如下:

情况1

系统启动后,它的shell也是一个进程在内存内有自己的一块空间,用来存储环境变量表或是读取到的命令等等,当我们在命令行中写下字符串mynum=100 后,会在它的上下文中使用malloc 开辟一块空间,用来存放对应的字符串,如下图:

在这里插入图片描述

  • 此时被shell存下的变量叫做本地变量,只在shell的内部有效

情况2:

当我们使用export指令后,系统会在环境变量表的第一个无效的内容处存放export后的字符串,或者可以理解为在环境变量表中使用malloc 开辟一块空间存放字符串

在这里插入图片描述

全局性

我们在Linux中使用指令或是执行可执行文件都是创建子进程的过程,而这些子进程的父进程都是shell,在子进程创建时,shell会将自己内部维护的环境变量表传给子进程,使其也可以使用环境变量,这就是环境变量通常具有全局属性,可以被子进程继承下去。

在这里插入图片描述

证明如下:

test.c 文件修改如下:

在这里插入图片描述

使用make指令生成对应的可执行文件,并执行,结果如下:

在这里插入图片描述

通过上图,我们看到在命令行中我们设置的环境变量mynum=50 在子进程中依然可以得到,父进程的确将环境变量交给了子进程。

证明:环境变量是可以被子进程继承下去的!

6.环境变量总结

  1. 环境变量本质就是一个内存级的一张表,这张表由用户在登录系统时,进行给特定用户形成属于自己的环境变量表。
  2. 环境变量是由shell维护的,创建子进程后shell会使用一些方法将其传给子进程,证明环境变量具有全局属性。
  3. 环境变量中的每一个,都有自己的用途,有的是进行路径查找的,有的是进行身份认证的,有的是进行动态库查找的,有的是用来进行确认当前路径等等。
  4. 每个环境变量都有自己独特的应用场景。
  5. 每一个环境变量都有自己的名字和内容。
  6. 环境变量都是从相关配置文件中读取出来的(所以每次登录环境变量是相同的,在家目录下的.bash_profile.bashrc中)

7.main函数的前两个参数

main函数是可以接收三个参数的,最后一个是接收env环境变量表的,而前两个是可以单独写的,用来接收选项

int main(int argc,char* argc[],char* envp[])

我们在执行指令时经常后待一些参数,比如使用ls指令时,会使用-l、-a等参数

在这里插入图片描述

ls也是一个可执行文件,该文件所在位置存放在环境变量PATH中,我们可以不去管它的位置,直接使用文件名即可运行,既然是可执行文件,那它对应的程序中一定有main函数,它main函数中的前两个参数就是用来接收,命令行中输入的选项的。

int main(int argc,char* argv[])
  • argv:存放命令行中传入的选项的地址(包含可执行程序这个字符串),第一个无效字符存放NULL
  • argc:表示传入的选项个数

接下来,我们来测试一下:

先将test.c 文件修改如下:

在这里插入图片描述

接着,使用make指令,生成可执行文件,执行如下指令

在这里插入图片描述

我们看到,父进程bash将命令行中的字符串使用空格分割,传给子进程main函数的argv 参数。

  • 这就是我们在使用指令时,对应的程序识别选项的方法原因。

我们接下来写一个小程序,来模拟选项的实现:

test.c 文件修改如下,功能为,只向可执行程序传输一个选项(不包含可执行文件名),执行对应的操作,若一个没有则返回一段提示,告诉用户需传输选项:

在这里插入图片描述

使用make指令,执行可执行文件,对其进行测试,如下:

在这里插入图片描述