兜兜零元 发表于 2024-9-23 07:14:35

初识Linux · 环境变量

目录
媒介:
下令行参数
环境变量
直接看征象
更多的环境变量
实行明白环境变量
媒介:

本日先容的是一个较为陌生的名词,环境变量,在学习环境变量之前,我们需要一定的预备知识,这个预备知识是下令行参数,所以本日我们先容环境变量的时候,先容序次是先先容下令行参数,然后直接看有关环境变量的征象,到更多的环境变量,最后我们实行来明白环境变量。
现在进入第一个话题,预备知识——下令行参数。
下令行参数

先容下令行参数我们从main函数开始,相信不少人是比力疑惑的,这和C语言的main函数有什么关系?还真有,只不过是我们最开始忽略了main函数的参数而已,相信这个时候有人开始有反应了,main函数我们学习的时候确实会有人带参数,只是因为没有方法传参进行调用,也就不了了之了:
5 int main(int argc,char* argv[])
6 {
7                                                                                                                                                                                                               
8                                                                                                                     
9   return 0;                                                                                                         
10 } 本日的下令行参数就从argc argv开始。
那么先来一段代码:
5 int main(int argc,char* argv[])
6 {
7   for(int i = 0;i < argc;i++)
8   {
9   printf("%s\n",argv);                                                                                                                                                                                 
10   }
11
12   return 0;
13 }
为什么写这样一段代码呢?我们不妨对参数进行一点分析,int argc说明argc是一个整形,背面的argc是一个char*类型的数组,就代表说这个数组的内容是char*,那么我们应该是可以实行进行打印的,所以我们写了如下代码,make一下之后,我们看看结果是什么:
https://i-blog.csdnimg.cn/direct/520a76917b484f888fbabf5870a6e421.png
结果是我们在下令行参数不管输入多少都会进行打印,而且打印序次默认是从左到右,即最开始的一定是./test,那么这是为什么呢?
我们再来看一段代码:
6 int g_val = 100;
7 int main()
8 {
9   int a = 1;
11   pid_t id = fork();
12   if(id == 0)
13   {
14   printf("a=%d&&g_val=%d\n",a,g_val);
15   }
16   return 0;
17 } 打印结果:
https://i-blog.csdnimg.cn/direct/1b57c8ff2f664ebea5616b2fb6e501a1.png
这个打印结果很简单,这里提问,子进程为什么能打印g_val的值呢?
我们都知道全局变量是在main函数栈帧创建之前就创建了的,按原理来说应该是和子进程没有关系才对,那么,子进程能打印这是怎么回事呢?
这里就得出来一个紧张结论,父进程的数据,默认能被子进程看到并访问!
我们现在有了两个预备知识:
1 main函数的下令行参数可以使用,下令行参数是我们输入得来的
那么作用是什么?不要忘记我们ls的不同选项了,是不是就可以联合下令行参数,雷同于通过下标的方式,来执行不同的功能了?这就是下令行参数要做的事。
2 父进程的数据默认能被子进程看到并访问
第三个知识是,我们寻常输入指令的地方,也就是下令行解释器,提问,我们是输入给谁的呢?为什么我们输入了对应的指令,就可以有相应的指令运行呢?
https://i-blog.csdnimg.cn/direct/b80e2724938546928de2bfe765db0407.png
这里,就是下令行解释器,我们寻常输入的ls cd等下令,输入了之后,在进程部分我们知道它们现实上也是一个一个的进程,那么它们的父进程是什么?
不管我们写了任何的代码,不管怎么运行,不管我们使用的是任何的指令,不管带了多少个选项,它们本质都是进程,我们打印出来它们的ppid,在ps内里,查对应的ppid,就发现是bash进程。
这个场景是不是很像VS中cin的时候,等待输入?
所以现实上我们的操作都是对bash进程操作的,虽然我们是运行了子进程,但是本质都是给的bash进程。
预备知识3:
3 下令行给的指令等,都是传给bash的
环境变量

3个预备知识已经就位,首先提一个问题,ls运行的时候是进程,我们自己写的代码运行的时候./test也是进程,它们两个都是子进程,凭什么我们自己写的代码就需要./ ,要在当前路径探求呢?ls等指令就不需要呢?
直接看征象

我们直接引出结论,因为有PATH这个环境变量的存在,我们可以使用echo打印出来看看:
https://i-blog.csdnimg.cn/direct/d7788616b16b4bf79bd1f682fdfdfde4.png
这样是不可的,我们需要$符号:
https://i-blog.csdnimg.cn/direct/a3d87eda1c63475e80e380e2d5514617.png
我们可以看到有多个路径,以冒号为分隔符。
https://i-blog.csdnimg.cn/direct/3c1bf780544e4dafb648879a94fd7c0d.png
而且可以看到,ls的指令是在bin目录内里,在PATH内里恰好也有,而查找下令就是根据PATH内里有没有对应的路径,如果没有对应的路径,就需要我们自己指定路径了。
这是PATH的用途。
https://i-blog.csdnimg.cn/direct/6fd8c0d312114595a3a3bead0319dd95.png
这样更加直观,我们可以指定路径,来执行我们所写的代码。
这是直接看征象部分,Linux中有全局设置,即是告诉编译器,应该去哪里探求下令。
那么我们如果想要和系统一样,直接执行呢?也就是说我们要修改PATH,或者说将可执行文件放在PATH内里的目录内里,我们先来试试第二种,将我们对应的路径加进去:
https://i-blog.csdnimg.cn/direct/0b145b990b984fb19e3dfe0024b0f6de.png
使用该指令,将我们的可执行文件地点的文件路径加进去即可,然后就可以执行运行。
这里有一个需要注意的点,test在Linux中是一个下令,如果我们的可执行文件是test的话,就会导致结果容易混淆,这里保举将可执行文件换个名字:
https://i-blog.csdnimg.cn/direct/e5c574b926da46dbbc8eacc2d9e1cb5c.png
此时就好了。
这是第二种,我们来试试第一种,直接修改PATH:
https://i-blog.csdnimg.cn/direct/4450fb1fa08340a98c408cc2e5f5287e.png
此时我们直接修改,然后会发现PATH的路径只有我们赋值的,这是一种覆盖:
https://i-blog.csdnimg.cn/direct/2f508927cbe6457fa4954cdf0e5cda9d.png
但是此时就会发现,bin目录的,或者是说原来的路径内里的指令都使用不了,但是我们的main照旧可以使用:
https://i-blog.csdnimg.cn/direct/9d02566b051a413cad3065d50779fd4b.png
好了,是不是感觉麻烦来了?什么指令都用不了了,此时,有同学会注意到为什么echo还可以使用?
这里就先埋个伏笔,我们通过这个征象,引入一个问题,我们打印出来的Hello world是来源于内存照旧磁盘呢?
答案不用多说,自然是内存,那么我们使用指令的时候,bash进程肯定是要先找到指令,那么去哪里找呢?联合我们打印Hello world,我们知道是先将字符串加载到虚拟地址,也就是到了内存内里,同理,bash找指令的时候,是不是应该到虚拟内存去找?
当我们登录到Linux系统的时候,很多设置文件是先加载到了bash进程,那么环境变量是否在设置文件内里呢?固然是,所以我们能看到的PATH不过是内存级的变量,如果我们重启一下,那么我们对PATH的修改就没有效了,因为设置文件我们没有修改。
那么对于设置文件和指令,我们可以有一个结论,因为bash要执行指令的时候,需要找到该指令,那么设置文件就一定比指令先加载到bash进程内里。
既然提到了设置文件,我们不妨看几个:
https://i-blog.csdnimg.cn/direct/fe7b3a7b892a4b1d8bad43166ce3fc23.png
对于vim来说,viminfo就是它的设置文件之一,所以我们yum的时候,黑白常方便的,因为它会帮我们下载对应的设置文件,我们就不用单独设置文件了。
更多的环境变量

我们现在了解了一个环境变量,我们来看看更多的环境变量:
https://i-blog.csdnimg.cn/direct/773aa57c40984c7195b8ffc5fd930781.png
因为图片巨细缘故原由,这里截图部分,我们使用指令env即可查出来一张表,环境变量表,内里包好了所有的环境变量,我们每个简单先容一下:
SHELL变量,外壳程序,可以明白为bash是它实例化的一个对象,HISTSIZE历史巨细,表现该呆板能存储我们指令的最大个数,我们平时使用指令是可以上翻下翻找我们使用过的指令的,那么查找是有个度,就是这个环境变量,是我们存储指令的最大数目,默认是1000.https://i-blog.csdnimg.cn/direct/deb8726c399a446ab21182a3100b9ab7.png
可以使用指令history来检察我们写过的指令。HISTTIMEFORMAT历史时间格式,PWD代表当前路径,它是可以变化的,因为我们不管在哪个路径下是用pwd都可以打印当前路径,就是因为它是变化的。HOME不用多少,当前用户的家目录。
https://i-blog.csdnimg.cn/direct/c4860ce34b2846348f25441ed37aa55e.png
带有UTF的环境变量是表现当前的编码是什么,比如这台呆板的编码就是UTF-8,下面谁人让人头皮发麻的是颜色设置。
https://i-blog.csdnimg.cn/direct/b0693c842a49472a900b8c03a6eb0f13.png
还有这些,比如PATH,USER等。
以上就是其他的环境变量。
那么我们能不能自己来点环境变量呢?固然是可以的:
https://i-blog.csdnimg.cn/direct/402542e94d0448318c8fb6671bf08c53.png
岂非这么简单?
https://i-blog.csdnimg.cn/direct/c1b78f0b9bce4ecf847d6618908d3d07.png
这也没有找到啊?https://i-blog.csdnimg.cn/direct/7e7752efc9c14256a5ec2edf91b94f81.png
为什么又可以打印呢?
哦~原来是因为HELLO是个本地变量,我们只需要知道一下本地变量就可以了,没啥用这东西,那么我们如何让HELLO变成环境变量呢?
https://i-blog.csdnimg.cn/direct/5a5a767f161e485ca2556db566e74151.png
export即可,如何取消我们设置的环境变量呢?
https://i-blog.csdnimg.cn/direct/ffccae5b99e44120b55a13fcc44e43dc.png unset即可。
实行明白环境变量

https://i-blog.csdnimg.cn/direct/c2007a86c8d74d7ebf80716f48e08aac.png
我们首先来看一个函数,我们想要通过代码的形式,来看到环境变量,所以我们使用environ,它是一个二级指针,不出不测,指向的是一个char*的数组,那么我们打印看看:
int main()
{
      extern char** environ;
      for(int i = 0;environ;i++)
      {
                printf("env[%d]:%s\n",i,environ);
      }
      return 0;
}
https://i-blog.csdnimg.cn/direct/4d0b590729c648f1ae4b15a9dbab426b.png
欸!这个东西,怎么那么,像我们刚才看到的环境变量?对!它们就是我们刚才看到的环境变量。
那么联合我们的预备知识2,父进程的数据可以被子进程看到,我们知道最开始加载到了bash进程环境变量,可以被子进程打印出来,那么在bash内里是如何对诸多环境变量进行管理的呢?
这里的environ是二级指针的数组,供子进程使用,我们不难推测,bash进程构造环境变量是靠的一张表,char* env内里存储的就是所有的环境变量,而environ指向的就是env数组,那么就可以通过下标的方式进行打印。
既然数据都共享了,父进程不妨直接给子进程两张表,一张表是下令行参数表,一张表是环境变量表。
此时,我们在下令行解释器输入的-a使用到了下令行参数表,环境变量表我们可以这样:
int main(int argc,char* argv[],char* env[])
{
      for(int i = 0;env;i++)
      {
                printf("%s\n",env);
      }
      return 0;
}

所以引入了main函数的第三个参数,env环境参数表,这里使用env作为判断条件,我们还可以证实一件事,argv[] env[]都是以NULL结尾的。
https://i-blog.csdnimg.cn/direct/a15466cd97ad488bbefffb3edada9f50.png
看一个库内里的函数,叫做getenv,简单的,我们直接实例代码即可:
int main(int argc,char* argv[],char* env[])
{
      char* str = getenv("PATH");
      if(str)
      {
                printf("%s\n",str);
      }
      return 0;
}

https://i-blog.csdnimg.cn/direct/67ba8ee9b84247dc88d872768f831d97.png
简而言之,getenv就是用来查找环境变量的。
所以现在查找环境变量有三种方式,一种是getenv,一种是main函数的参数,一种是environ二级指针。
我们现在进入最后一个话题,为什么我们最开始修改了PATH,但是仍然可以执行echo下令呢?
我们如果export一个环境变量,env内里可以查找到:
https://i-blog.csdnimg.cn/direct/119937b7789941b4a4a705eb6572b7fe.png
但是我们联合父进程的数据能被子进程看到,但是子进程的数据不应该被父进程看到这个点,岂非bash执行export不会创建子进程吗?
是的,如果创建了子进程,bash的env表就是不能看到HELLO,所以这种指令是特殊指令,叫做内建下令,是由bash自己来执行的,不是创建了子进程的。
到此,环境变量就结束了!尚未不清楚的点后续更新~
感谢阅读!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 初识Linux · 环境变量