Linux:环境变量

基本概念

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数

如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

在Linux操作系统启动时,会创建一些变量供运行时使用,这些变量就是环境变量。

比如:我们执行指令时,可以直接输入指令执行,而执行我们编译生成的可执行程序,就需要加上路径才能调用,这就是因为Linux中有一个环境变量存储了一些路径,执行指令时会默认去这些路径查找相应的指令,不需要加路径,而我们自己的程序没有在这些路径下,basn命令行在默认的路径下找不到这个程序,所以无法执行。

这个存储了一些路径的环境变量叫做PATH

我们可以使用echo $name来查看name环境变量的内容:

在这里插入图片描述

可以看到,PATH存储了多个路径,路径之间使用:间隔。

所以如果我们将自己的可执行程序放在这些路径下,也可以直接调用,这时,我们的可执行程序就相当于是指令了;或者我们也可以将一个路径加到PATH中,那么在该路径下的可执行程序也都会成为指令。

比如我们有如下程序:

在这里插入图片描述

编译后生成test.exe,然后我们将当前路径添加到PATH中,就可以直接调用test.exe了。
在这里插入图片描述
需要注意:PATH本质上是一个char*指针,所以它的内容是字符串,我们可以使用PATH=echo $PATH:newpath来为PATH添加新路径,如果直接PATH=newpath,那么之前的那些路径下的指令就都不能直接调用了。

除了PATH,还有几个重要的环境变量:

USER:当前用户

PWD:当前路径

HOME:指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)

SHELL:当前Shell,通常是/bin/bash

在这里插入图片描述

可以看到USER环境变量记录了用户名,用来进行访问文件时的权限审核。HOME记录了用户的家目录,所以不同的用户使用pwd ~会进到不同的家目录。

创建环境变量

export命令用来创建临时变量。

export NAME=XXX

在这里插入图片描述

env命令用来显示所有环境变量:

在这里插入图片描述

unset用来清除环境变量:
在这里插入图片描述

可以看到,TEST环境变量被清除掉了。

环境变量的组织方式

其实每一个环境变量都是一个char*指针,指向一个字符串内容,而且所有环境变量都被存储在一个指针数组中。

在这里插入图片描述

每个程序都会收到一张环境表,环境表就是那个指针数组,每个指针指向一个以’\0’结尾的环境字符串,环境表的最后一个元素为NULL

通过代码获取环境变量

命令行第三个参数

main函数是有参数的,main函数的参数就是为了接收环境变量设置的,前两个参数如下:

int main(int argc, char* argv[])
{}

argcint类型的变量,而argv是一个char*的数组(类型为char**的指针)。其中argv接收的就是我们的输入及选项,而argc接收的是argv中元素的个数(不包含NULL)。

现在我们在test.c中写main函数接收这两个参数:
在这里插入图片描述

然后我们执行./test

在这里插入图片描述

可以看到,argv中存储的就是我们输入的选项。

所以在main函数内部就可以通过argv来执行不同的代码块,从而实现不同的效果。

这就是我们输入的指令可以携带不同选项的原理,bash会根据argv来决定执行动作。

除了这两个参数,main函数还有第三个参数:

int main(int argc, char* argv[], char* env[])

第三个参数为char*指针数组(类型为char**的指针),用来接收环境变量表,也就是environ表。

我们修改test.c,让其输出所有的环境变量:(黄色高亮部分是因为没有使用到参数)
在这里插入图片描述

在这里插入图片描述

可以看到,该程序的运行结果和我们执行env指令的结果是一致的。

所以程序中可以有两张表命令行参数表环境变量表,根据这两张表,main函数可以执行不同的动作。

getenv

如果在程序内,我们想要获取一个环境变量的值,这时通过argv就显得非常笨重,我们需要遍历argc数组,并比较字符串前几个字符和我们想要获取的环境变量的字符串是否相等,此时getenv()函数就可以解决这个问题。

const char* getenv(char* name)

getenv()函数可以根据环境变量的“名”,返回环境变量的”值“,使用该函数需要包含<stdlib.h>
在这里插入图片描述

可以看到,getenv函数的返回值和environ以及argv[]中的数据是一致的。

environ

environ是一个外部变量,在程序内部声明后才可以使用

environ是一个char*数组,本身类型为char**

environ指向的就是环境变量表,和main函数接收的第三个参数env一模一样。

在这里插入图片描述

可以看到运行该程序,打印结果env中的内容一致。

环境变量表

通过上面的例子,我们可以看到:env指令可以在bash命令行中直接调用,并输出环境变量表,env可以作为main函数的第三个参数传递给main函数,其内容和env一致,environ声明后可以在程序内部直接使用,其内容和env一致。

他们三者之间是什么关系呢?
在这里插入图片描述

可以看到,environmain函数的第三个参数的地址相同,所以它们就是同一个变量,只是名字不同。

bash会维护一张环境变量表,指令env就是输出这张环境变量表,而main函数的第三个参数、extern外部变量都是这张表的地址,它们指向的都是同一张表。

环境变量的全局属性

环境变量是可以继承的,子进程的环境变量就是父进程的环境变量,也就是说环境变量具有全局属性。

比如:我们在bash命令行调用的进程,都是bash的子进程,所以这些进程可以拿到bash维护的环境变量表。

bash本身在启动时,会从操作系统的配置文件中读取环境变量信息。
在这里插入图片描述

可以看到,父子进程的环境变量表是相同的。

本地变量

bash命令行直接创建的变量就是本地变量:

在这里插入图片描述

而本地变量是不会进入环境变量表的:
在这里插入图片描述

我们可以通过set查看系统中的所有变量,包括环境变量和本地变量。

本地变量不会被子进程继承,只在本bash内部有效。

本地变量的意义在于:我们需要有一些变量,不被子进程继承,只在本bash内部有效,这些变量就是本地变量。

如果想要将环境变量变为环境变量,可以使用export NAME来实现。

可以使用unset NAME取消本地变量或环境变量。

命令

在这里插入图片描述

问题来了,既然本地变量是不会被子进程所继承的,而我们在bash命令行运行的指令都是bash的子进程,那为什么echo可以知道local_virtual的值呢?

原因是:命令行上调用的指令,不一定会创建子进程。

命令分为两种:

  1. 常规命令:通过创建子进程完成

  2. 内建命令:bash不创建子进程,自己亲自执行,类似于调用了自己写的或系统提供的函数。

cd命令就是典型的内建命令。当命令行调用cd命令时,如果创建子进程,修改的应该是子进程的路径,不会影响到父进程bash的路径,这样cd就失去了自己的作用,所以cd指令要设计成内建命令。

在这里插入图片描述

这个程序可以改变自己的工作路径。
在这里插入图片描述
可以看到,这个程序成功改变了自己的所处路径(不是存储路径)。

所以bash命令行也是同理,bash可以对我们输入的指令进行判断,如果是cd指令,就不创建子进程,直接调用chdir即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值