Linux【环境变量】

环境变量

一、基本概念

(1) 环境变量基本介绍

环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。是在操作系统当中,由系统开机之后帮我们维护的一些系统运行时的动态参数。,环境变量通常针对场景不同,软件不同,环境变量有不同的参数。
如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。

(2) 以./作为切入点去了解环境变量

在linux上写代码,编译生成一个可执行程序,需要./a.out运行,为什么要带./,而linux上指令如cd ll…本质也是一个可执行程序,而它们却不带./去运行。
其实自己写的程序和linux系统自带的指令并没有什么区别,只不过别人写的软件被纳入了linux基本指令的范畴,自己写的只能自己写,在本质上都叫可执行程序。

为什么运行系统指令就不用带./,而自己写的程序得带./ ?
.是当前路径,/是路径分隔符,而./名字是用相对路径的方式定位可执行程序的,当然也能用绝对路径去访问。以上的原因是因为我们默认的程序在系统当中是会存在一个环境变量,这个环境变量是能够帮我们通过该变量在系统当中特定路径下去帮我们搜索对应linux基本指令,执行一条命令的前提是先找到它,所以系统存在一个环境变量:PATH,如果读取内容 用echo ¥PATH指令查看,综上,为什么能执行touch pwd等等指令,根本原因是因为这些指令会在特定的环境变量所指明的若干路径一个一个去找,找到了就自动执行,我们写的可执行程序对应的路径没有在以上那个环境变量里,所以执行无法直接可执行程序,所以用户得自动指明对应的路径,所以这个PTAH称环境变量。PATH就是可执行程序的搜索路径。

如果执行自己的程序不添加任何的路径,我们该怎么做。
在这里插入图片描述
上图我们可以看到,用which 查看myenv程序,发现它不在上面的环境列表里,可以尝试将当前的路径添加到环境变量, 用这个是导入环境便令需要用到一个指令export。
操作:export PATH=¥PATH:/root(当前路径) 如下:
在这里插入图片描述
在linux中,把对应的可执行程序拷贝到系统默认路径下,让我们可以直接直接访问的方式,相当于linux下的安装。如果不想要了,直接rm 路径 -rf ,这个过程就相当于卸载如下图:
在这里插入图片描述

比如当我们配置JAVA 以及python环境变量的时候,实际上是把JAVA的虚拟机,python的解释器装上,装好之后,这些可行执行程序在系统某些路径下,但是我们的操作系统本身是没有办法直接找到虚拟机,解释器,所以当时我们配的环境变量也是PATH,配置之后,在命令行上,或者在程序里想运行找到对应的虚拟机,解释器,就能直接去找。

(3) 再次认识环境变量

环境变量通常是在某些特殊场景当中需要由系统帮我们维护的一组变量,只要是变量,就有变量名和变量内容,变量内容通常用来让程序在一些具有共识型的资源当中进行资源访问,比如我们所有的程序在搜索的时候不用再全局搜索,而是在系统user/bin路径下去找可执行程序,比如头文件,环境变量帮我们自动去指定,同时用户在登陆的时候,系统当中也需要有环境变量来记录我们是谁。

比如:echo ¥USER:代表当前用户是谁。
文件里为了区分是谁,要做一个关键的的动作,需要判断当前用户是否对这个文件有读写权限,首先做是用户是否是这个文件的拥有者,所属组等,系统怎么怎么知道当前用户是谁,就是有环境变量的存在,在登录的时候就知道我们是谁。所以环境变量记录了这个用户正在使用linux是谁,当访问某些文件,就需要先拿着对应环境变量的用户名,和拥有者,所属组作对比,才识别出来是谁,知道之后,才确定对某个文件是否有读写执行。

二、常见环境变量及相关指令

常见环境变量:
PATH : 指定命令的搜索路径。
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)。
SHELL : 当前Shell,它的值通常是/bin/bash。
echo $NAME //NAME:你的环境变量名称。
和环境变量相关的命令:
1.echo: 显示某个环境变量值
2. export: 设置一个新的环境变量
3. env: 显示所有环境变量
4. unset: 清除环境变量
5. set: 显示本地定义的shell变量和环境变量

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

1、命令行第三个参数
2、通过第三方变量environ获取
3、常用getenv和putenv函数来访问特定的环境变量
以上具体操作在第四条内容讲解:

四、main函数第三个参数:环境变量参数

int main(int argc, char *argv[], char *envp[]),实际上main函数是可以传三个参数的。
第三个参数是环境变量表。如果我们自己没有写编译器自动加上。每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串。这是环境变量的组织方式
在这里插入图片描述

第三个参数指针数组,指针数组是数组,里面放指针。如上图。指针是一个字面值,它是数据,指针变量保存指针的数据也即地址。里面存的是字符指针,指向的是一个字符或字符串首地址。而如上指的就是一个一个的字符串。最后必以NULL结尾。

(1) 第一种方式通过envp获取环境变量

如图代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char* argv[],char* envp[])
{
    
    
    for(int i = 0; envp[i]; i++)
    {
    
    
       printf("envp[%d]:%s\n", i, envp[i]);
    }
}

在这里插入图片描述

上面代码可以看出,envp它是一张传递当前进程的环境变量表。给我们呈现的是一个一个环境变量字符串。

(2) 第二种方式通过environ获取环境变量

如果main里面不带参数,就像我们平常写的程序,也想获取环境变量,这也是可以打印出来的,因为C/C++给我们提供了全局变量。 *extern char environ,它和char envp[]是等价的。

int main()
{
    
    
     for(int i = 0; environ[i]; i++)
    {
    
    
       printf("environ[%d]:%s\n", i, environ[i]);
    }

}
   

在这里插入图片描述
以上我们可以知道进程内部本身就有环境变量。
以上需要自己要花时间自己遍历这张表,里面做字符串匹配,查找环境变量,以上2种没必要。

(3) 第三种方式通过函数获取环境变量

但以后通过调用某些函数获取环境变量时,查的时候就是传给表里面去做字符串匹配帮我们把要到的字串拿到。

如下 三组代码:
在这里插入图片描述

    char *own = getenv("USER");
    if(strcmp(own, NAME) == 0)
    {
    
    
       printf("这个程序已经执行\n");
    }
    else
    {
    
    
       printf("当前用户 %s 非法用户 无法执行\n", own);
    }

    char *pwd = getenv("PWD");
    if(pwd == NULL) perror("getenv");
    else printf("%s\n", pwd);

通过以上举例,这叫做环境变量,我们的程序是可以存在着一些系统给我们提供的必要的环境变量,可以让我们结合环境变量去写出来与系统强相关的代码。

(4) 再次深入理解环境变量

环境变量本质上就是一个内存级的一张表,这张表由用户在登录系统的时候,进行给特定用户形成属于自己的环境变量表。
环境变量中的每一个,都有自己的用途,有的时进行路径查找的,有的进行身份认证的,有的进行动态库查找的,有的是用来进行确认当前路径等,不同的环境变量在软件当中有不同的应用场景,而环境变量是最根本的,由系统帮我们形成的一张表。

(5) 为什么是内存级

如果我们把环境变量改了,再重新登陆的时候就好了,说明刚刚改,不影响大局,说明是在内存改的。如果没有被加载到内存之前在哪,环境变量实际上都是从系统的相关配置文件中读取的,在家目录可以找到 .bash_profile和.bashrc这个两个文件,这个东西本质上是shell脚本。所以用户在登录成功的时候,系统会重新读取配置文件,把配置文件的脚本执行,帮我们自动生成对应的环境变量。

(6) 如何去理解变量

以前变量是语言级别的,开辟空间去定义,我们能理解。而现在的环境变量的是内存级的,这个内存级究竟是什么,究竟在哪,我们在执行命令由bash帮我们去执行,那么我们在命令行中除了执行命令,还支持 命令行式子的自定义变量:如val=100。登录自己的机器成功时,OS给我们创建一个shell,专门为我们提供命令行解释,而shell是一个进程,是可以读取我们的命令和命令行,比如在命令行# val=100,那么这个shell就会读val=100这个字符串,shell启动会维护刚才那个环境表的,如果用export,那么shell把我们传进来的字符串,直接从数组当中找到没有使用的数组下标,用下标指向这个字符串,其实就是shell,malloc一个内存空间,把刚才写的字符串,直接放到堆空间里,用指针指向它。如果没加export,或者不是环境变量,同样malloc一个空间,然后把val=100这样的字符串保存到自己的shell内部,所以所有的命令都是shell的子进程,当执行命令的时候,在父进程执行子进程,创建fork,还可以让父进程给子进程传参,把自己的表传给子进程,让它拿到表。
在这里插入图片描述

(7) 结合变量再谈环境变量

如何理解环境变量,在我们登录的的时候,因为shell是一个进程肯定在内存,只要在内存当中在shell内部维护的一张表,也称之为内存级的表,换言之,环境变量在shell当中,当在创建执行新的子进程,就自然而然将我们的环境表交给子进程。说白了,我们的环境变量是在由shell自己的内部去维护的。
证明:在这里插入图片描述
在这里插入图片描述

所以我们导入的这个nza环境变量是在做什么?其实就是把这个环境变量设置到shell的进程内部,shell解释这个命令把它们当成字符串,再把它们添加到环境变量表,shell启动的时候是从系统的配置文件读取的表,再初始化的表。

证明父进程把环境变量表经过一定的参数方式交给了子进程,那么此时相当于子进程可以获得刚刚获得在shell当中导入变量
在这里插入图片描述
如上可以看到,所以环境变量是可以被所有的子进程进程的。也就是说在命令行导入了个环境变量,未来是可以让子进程使用的。说明全局变量具有全局属性
带export是将一个变量导入环境变量,可以被子进程继承下去,没带export 用echo¥kd也可以打印出来,这叫做本地变量,不可以被子进程继承。export做的工作就是把本地变量添加到环境变量表中。echo能打印出来是因为它是内键命令。

五、main函数前两个参数:命令行参数

(1) 理解命令行参数

main 第一个参数argc,和第二个*argv[]
*argv[]也是一张表,里面包含一个一个指针,指向的是一个一个字符串,它也是一个数组,第一个参数就是该数组的个数。
先遍历它看下结果:在这里插入图片描述
其中在命令行当中输入时,在shell看来就是一个字符串,既然是字符串就可以以空格做为分隔符,拆成一个一个的子串,第一个称为可执行程序,把后面参数 -a -b…称为参数选项,当我们调用env程序的时候,在main函数当中,有一个argv表,个数由argc决定,0号下标就会指向传进来的第一个字符串如env,1号下标以空格为分隔符的第二个子串,
最后以null结尾。其实就是shell把我们输入的一堆命令行即子串,在内部会把它们切割成若干个以空格为分隔符的子串,把每一个子串的地址放到argv数组里,制作这个表是由bash,子进程用这个表。

所以argc就是命令行参数对应的个数,argv就是命令行参数对应的各个子串对应的起始地址就是表。

(2) 命令行参数用途

在这里插入图片描述

以上通过这个说明代码,如果在命令行参数当中,可以根据不同的选项可以让对应的同一个程序执行不同的功能。就像执行ll -s -a -i 有不同的表现,本质上就是命令可以有自己的选项,这个命令是C语言写的,这些选项就以字符串的形式通过命令行参数传递给了程序,对应的程序内部就会对选项做判断,这样就让一个软件可以携带不同的选项,就可以表现不同的现象。

猜你喜欢

转载自blog.csdn.net/m0_59292239/article/details/129317775