目录
若要谈环境变量,那么首先得认识命令行参数。
一、命令行参数
1、由带参数的main主函数来认识命令行参数
我不知道大家有没有过疑惑,我们一开始学习C语言就知道,我们写代码一定会写的一个主函数main只能有一个,并且这个main函数的参数还是可带可不带的,这就很让人疑惑,我们经常用的就是不带参数的场景,那带参数的main函数该如何用呢?
带参数的main函数有这两个参数:
- argc:指针数组argv中元素的个数
- argv:指针数组,内部元素都是char*类型的字符串
2、指针数组argv里面有什么
既然main函数带参数,那一定有他的道理,不妨先看看这个指针数组里面有什么,写代码将里面的内容打印出来:
我们直接看运行结果:
在这里,我首次运行可执行程序的时候,我们发现里面存放的字符串竟然是'./process',接着我们再输入运行的命令的后面加上 '-a',再运行发现里面有了存放的第二个字符串 ,是'-a',我们再在运行命令后面多加几个试试,以空格作为区分,得到的结果是:我们在命令行输入的都被当成字符串存放到了argv指针数组里。并且该指针数组一定要以NULL结尾
在我们输入的这串命令中,前面的一般都是我们程序的路径+名称,后面我们一般称他为进程匹配的选项。
我们此时在命令行输入的命令,都被当成了命令行字符串写进了argv指针数组中。
3、为什么要有命令行参数
我们先写出来代码:
然后开始运行:
我们可以发现,我们的每一个选项都对应着一个功能,这是不是很像我们在Linux里面使用的指令形式:
那上面ll命令解释,我们的ll命令后面跟不同的选项就对应着不同的功能。
所以,为什么要有命令行参数:命令行参数本质上时是交给程序不同的选项,用来定制不同的程序功能,就比如命令中会携带很多的选项。
4、把命令行选项放入指针数组的是谁
我们先来看一串代码:
我们定义一个全局变量g_val=10000,其它的就是父子进程,我们分别打印出他们的pid和ppid
然后运行:
我们都知道子进程接着执行父进程后面的代码,但是 为什么子进程也会得到g_val的值呢?
因为子进程会继承父进程!父进程的数据,默认能被子进程看到。
那我们在上一串代码中,它的父进程是谁呢,他跟我们一个普通进程一样,最开始执行的进程父进程都是bash:
这里不绕弯子,我直说
我们的命令行选项是被父进程bash放入指针数组argv中的,我们的bash会malloc一串数组来存放,那我们的进程是如何看到父进程开辟的这段空间,并且拿到里面的数据的呢?这就是我上面所讲的,子进程会默认看到父进程的数据。
所以我们的进程是能看到父进程构建的这个数组的。
5、命令行参数存在的意义
我们知道了我们在Linux命令中的指令都是由带参数的main函数来实现的,每一个命令函参数都对应着不同的功能,我们可以查询一下Linux中的指令所在,以ls命令为例:
我们查询可知,ls命令其实是在我们的/usr/bin目录里,是由C语言写成的程序。
所以,命令行参数就是一种可以给main函数传参的方式,在未来我们可以写可变选项的程序,由一个程序实现不同的功能,相当于我们的指令。
二、环境变量
我们上面说到,命令行参数和我们的指令一样,那你们没有一个疑惑:为什么ls命令可以直接用就可以使用其功能,但是我们自己写的process还必须带上./process -a/-b/-c/-d呢?
我们想要使用这个功能,我们首先就要运行它,那ls是怎么被运行的呢?
1、环境变量PATH
Linux中,存在一些全局的设置,你使用一个命令时,命令行解释器会顺着这个命令所在的路径开始寻找可执行程序。就比如PATH,它是我们Linux中搜索可执行程序的默认路径
环境变量有很多,PATH就是其中一个,我们先查看一下PATH这个环境变量里面有什么:
使用命令:echo $<环境变量>
有着一个又一个的路径,以':'为分隔符被隔开。
我们可以看到第二个路径为/usr/bin,这不就是ls命令所在的路径吗
在我们刚登录Linux系统的时候,系统中的很多配置就已经加载到了bash进程中,我们也知道,bash会将命令行选项放入指针数组argv,所以bash在执行命令时,它必须先找到这个命令,因为未来需要加载它。
所以,我们的process是不能直接被执行的,必须'./',因为process可执行程序的路径不在PATH当中。
2、将我们自己的可执行程序变成系统指令
那我们如果有这个需求呢?我想执行我们的命令和系统指令一样,不带'./',我们就需要把其可执行程序路径放入PATH环境变量里。
如何放:使用指令 PATH=&PATH:<可执行程序的路径>
我们pwd复制粘贴目前路径到命令后面,就可以把我们自己的可执行程序变成系统指令一样的用法了,不用再加./
我们查看一下PATH中是否有我们干刚刚添加的路径
在最后我们可以看到正是我们刚刚添加的我们的可执行程序所在的路径。
3、默认查到的环境变量是内存级的
我们在PATH添加完后我们可执行程序的路径之后,可以像系统指令一样使用,那我们可以一直使用吗?答案是不可以的。当我们重启Linux系统时,我们手动添加的路径就会消失,只会留下系统默认存在的系统指令的路径。
原因就是:当我们每次重启Linux系统时,系统中的很多配置会被加载到bash进程里,bash既然是一个进程,那么他一定会在内存里,我们新添加的只是添加到了环境变量PATH里,再被放入内存之前,我们的环境变量都在系统对应的配置文件里。而我们添加的可执行程序的路径并不在可配置文件里。
那么我们想每次重启时可以直接使用我们自己的可执行程序,那么该如何把自己的可执行程序路径放入系统对应的可执行文件里呢?这个文件又在哪里呢?
4、如何把我们的可执行程序路径放到系统对应的配置文件里
我们在Linux系统中,每个人都有自己的家目录:
在我们的家目录底下,我们可以看到这样的两个文件,我们vim打开:
我们可以看到PATH相关的配置。
我们在.bash_profile文件中,将我们的process可执行程序文件放在PATH路径配置的后面
重启系统
我们直接process:
可以发现,已经可以使用了
5、如何创建自己的环境变量
5.1创建
使用命令:export <环境变量名>=<环境变量的内容>
5.2 查看
使用命令:env
我们查看一下我们刚刚创建的环境变量:
有点多,我们使用管道筛选一下:
但是目前我们作为初学者,创建自己的环境变量暂时还没有用处
5.3 删除
使用命令:unset <环境变量名称>
删除之后再查发现查不到了。
三、通过代码方式进一步认识环境变量
1、查看现象
我们先来认识一下environ是什么,二级指针,现在你只需要知道它是一个指针数组的初始地址
接下来我们打印这个指针数组里面的内容:
打印结果可知:我们将环境变量打印了出来,这些正好与我们使用命令env查看到的一样
2、现象解释
在操作系统启动之前,我们的配置文件存在于我们的磁盘当中,登陆之后,进入到我们的bash内存中,所以,环境变量也都在bash进程中了,我们上述代码打印出所有的环境变量这也不奇怪,因为我们的子进程默认是能看到父进程的数据的。这都是我们上面刚刚讲过的。
那么,环境变量是如此的多,bash进程是如何进行管理的呢?重点来了 !
bash进程会维护一张表,这张表的名字叫做char *env[],熟悉吗?和bash维护命令行参数的一张表char * argv[],是不是很相似。那我们的子进程虽然能看到父进程bash的数据,那他是怎么找到这张表的呢?就是通过我们刚刚写的extren char **environ,它指向了指针数组env的首部,也就是这个指针数组的地址。
综上,我们可以知道,bash进程启动时,默认会给我们生成两张表:
- argv[]命令行参数表:由用户输入的命令行来
- env[]环境变量表 :由系统配置文件来
3、main的第三个参数
既然能够生成两张表,那系统提供了一个更为简单的方法让我们去找到环境变量,那就是main函数的第三个参数:char *env[],与我们的char *argv用法相同
我们也可以使用这种参数调用的方式来让我们找到环境变量:
所有内容已讲完,感谢大家。