【Linux】初识环境变量
创始人
2024-05-21 18:01:29

文章目录

      • 环境变量引入
      • 初见环境变量
      • 和环境变量有关的指令
      • 如何通过代码获取环境变量
        • getenv()
        • main函数的命令行参数
        • 第三方变量environ
      • 程序变量可以继承给子进程

环境变量引入

Linux中有各种指令,

每个指令其实都是一个可执行程序:

image-20230131124007311

和我们自己写的C语言代码编译生成的可执行程序一样。

当我们在运行自己的可执行程序时需要加上路径./exe

其实就是为了让命令行解释器知道我们要去执行哪个程序,

但是当我们执行某条指令时却不需要加路径限制,

命令行解释器好像自己就能找到这条指令对应的可执行程序执行它。

而做到这一点其实就是因为环境变量的存在。


初见环境变量

对于上面提到的那种情况,其实是因为环境变量PATH的存在。

PATH是指定命令的搜索路径,

我们可以通过echo $PATH的形式来查看:

image-20230131124457725

可以看到PATH有好多路径,

不同路径间通过 冒号 “ : ” 分割,

可以看到红框框出来的就是此前man指令所在的目录。

当然环境变量还有很多,

比如我们使用pwd命令输出当前目录时,

pwd是一个可执行程序,与我们所在的那个目录没有任何关系,

它是怎么能实时知道我们在哪个目录的呢?

其实还存在一个名为PWD的环境变量:

image-20230131192149055

又或者使用指令cd ~会跳到用户所在目录,

可执行程序cd又是怎么知道我们的用户目录是哪呢?

其实还存在一个名为HOME的环境变量:

image-20230131192418037


和环境变量有关的指令

echo: 显示某个环境变量值

上面提到了,我们可以用echo $name的方式来输出一个环境变量的内容。

env : 显示所有环境变量

想看看所有的环境变量?env(environment variable)满足你:

image-20230131193443837

export : 设置一个新的环境变量

首先我们可以在命令行定义变量:

image-20230131193612437

但此时a只是一个本地变量,我们无法通过env命令查看到它

一个办法就是用export命令把a设成全局变量:

image-20230131201051841

当然,我们还可以用export来修改环境变量。

当前这个目录下面有一个输出hello world的可执行程序my_test

我们将my_test所在目录导入环境变量PATH中:

export PATH=$PATH:<路径>

这样运行my_test的时候就不用加路径了:

image-20230131201817636

但是这样做只是临时的,如果再开一个shell就不支持了,

因为这样定义的只是在当前命令行进程中定义的,

对其他命令行解释器没有影响。

当然,如果想创建一个自己的指令,

也可以将可执行程序拷贝到系统PATH指向的目录中。

unset: 清除环境变量

我们可以用unset + 变量名清除一个环境变量或本地变量:

image-20230131204145322

当然也可以把环境变量清除掉:

image-20230131204233418

如果不小心将PATH等系统提供的环境变量清掉了不要担心,重开就好了:

image-20230131204711251

set: 显示本地定义的shell变量和环境变量

我们可以用env打印所有环境变量,

同时也可以使用set打印所有的本地变量和环境变量:

image-20230131210728431


如何通过代码获取环境变量

getenv()

上面我们可以通过echo、env等方式从命令行获取环境变量,

我们可不可以通过自己写的程序获取环境变量呢?

和用系统调用接口getpid()获取进程的PID一样,

Linux同样提供了接口getenv()获取特定的环境变量:

image-20230131211756634

RETURN VALUEThe getenv() function returns a pointer to the value in the environment, or NULL if there is no match.

description那儿提到了一个叫environment list的东西,

这其实是一个环境表,本质上就是一个字符指针数组,每个指针指向一个环境变量:

image-20230131212924939

这其实就是环境变量的组织方式,每个程序都会这样收到一张环境表。

下面就用一下试试:

#include 
#include int main()
{char* path = getenv("PATH");printf("path=%s\n", path);return 0;
}

image-20230131213754298


main函数的命令行参数

main函数其实也能有参数:

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

这三个参数叫做命令行参数。

下面对这三个命令行参数进行一一剖析。

首先argcargv是一块的。

可以看出argv是一个字符指针数组,它有几个元素呢,就是argc个。

当我们什么也不做时看看它都有什么内容?

image-20230131220250874

什么都不做时它只有一个信息,就是运行程序时使用的路径位置。

我们再试着运行test时加个命令行参数:

image-20230131220521748

所以为什么我们使用lsrm等命令时使用不同的命令行参数会有不同的运行效果,

这个小实验应该能给出我们答案。

下面再看第三个参数env

上面我们提到了,每个程序都会收到一张环境表,

也就是一个指针数组,env其实就是指向这张环境表的。

所以我们可以通过遍历env来获取所有的环境变量:

image-20230131221125112


第三方变量environ

当然,main函数可以用env来获取环境变量,

但还可以通过外部变量envrion来获取,它和env并无本质差别,

都是指向environment list的一个指针。

libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明:

image-20230131222544325


程序变量可以继承给子进程

我们可以试着一个本地变量,并用export将它导成环境变量:

image-20230131224219201

然后我们试着在代码中用getenv()接口获取我们定义的环境变量:

image-20230131224621671

发现获取到了,这里可以说明一点,环境变量是可以继承给子进程的

为了加强验证这点,再看下面的现象:

image-20230131225148907

右边那个是新开的终端,结果就截然不同。

我们称左边的命令行为bash1,右边的命令行为bash2,

可以看出来,my_val是定义在bash1中的一个环境变量,

在bash2中并不存在。

在bash1中运行的进程test是bash1的子进程,

在bash2中运行的进程test是bash2的子进程,

而只有bash1的子进程拿到了my_val。

另外,我们重新定义my_val为本地变量,

试试命令行运行的子进程是否还能拿到:

image-20230131225518992

说明只有环境变量才可以被子进程继承,本地变量不可!

这样就有一个问题,按理来说echo也是bash的一个子进程,

那为什么echo就可以获取到本地变量呢?

Linux下大部分命令都是通过子进程的方式执行的。

但是,还有一部分命令,不通过子进程的方式执行,而是由bash自己执行,这种命令叫做内建命令,而echo就属于这种内建命令。

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...