• 【Linux】Linux的环境变量(PATH、env、子进程继承环境变量等)


    环境变量

    1、从一个小案例认识环境变量PATH

    我们在shell中通过file查看文件信息,看到我们常使用的指令都是可执行文件(exe)。

    在这里插入图片描述
    我们自己编写的程序,毫无疑问也是可执行文件。

    在这里插入图片描述

    我们发现一个问题,在软件执行的时候,我们在任何路径下都可以使用ls、pwd等系统自带的,而我们自己的软件需要确定路径才能允许。

    如果要让自己写的程序直接输入程序名就能运行,该怎么办?

    • 通过环境变量PATH
      命令echo $PATH 查看系统的所有指令的路径。

      执行的程序的路径都在PATH变量里,我们可以把我们程序的路径放在里面,这种环境变量属于一种内存级变量,重启会恢复。
      通过export PATH=$PATH:添加的程序所在路径
      :前面$PATH代表原先的添加,:后代表添加程序所在的路径。
      在这里插入图片描述

    • 通过添加到指令空间

      我们所用的系统指令文件一般都是在/usr/bin目录下的。
      在这里插入图片描述
      我们可以将我们的程序拷贝到系统安装指令的空间/usr/bin中。
      在这里插入图片描述
      在这里插入图片描述

      但是这种方式非常不推荐,因为我们写的程序没经过测试,可能会污染指令池。
      所以测试完,记得删除。
      在这里插入图片描述

    通过这个小测试,我们知道了如果我们想通过程序名直接运行程序,需要让操作系统知道我们程序在哪。
    上面第二种方式很好理解,就是作为文件放在和其它系统指令所在一样的空间。
    那么 第一种方式通过环境变量是如何做到的? 以及

    什么是环境变量?PATH具体是什么?

    首先
    一个软件需要运行 >> 操作系统就必须要找到可执行程序 >> 需要在特定的路径下找 >> 操作系统启动时默认从配置文件中读取曾经将软件安装到了哪些路径 >> 当软件启动,操作系统就将对应路径导入到内存里构建了一个内存级变量 >> 环境变量PATH因此产生
    冯诺依曼体系规定,程序需要运行必须先加载到内存。)

    其中配置文件就是每个用户目录下的 .bash_profile,在用户每次登录系统时被读取,里面所有命令都会被shell执行。包括环境变量的配置命令。
    在这里插入图片描述

    PATH当操作系统在启动命令行解释器shell的时候,导入到shell的上下文当中,当我们执行相应的指令时,就必须通过PATH的方式,让系统通过PATH指定的路径去执行对应的可执行程序。

    并且,操作系统在启动bash为我们做一些命令行解释的时候,必须提前准备一些变量,变量中包含单个或多个程序需要用到的信息,这些变量就是环境变量。

    综上:简单来说,环境变量是一堆操作系统为解释命令的变量,其中PATH是记录程序所在完整路径的变量。

    2、常用的环境变量相关指令与系统调用

    • env
      首先通过env可以查看系统在启动后默认导的所有环境变量。
      这里截取一部分
      在这里插入图片描述
      当然也有PATH
      在这里插入图片描述

    • set、unset和本地变量
      首先本地变量和环境变量定义名字建议大写,内容建议加双引号!
      本地变量可以直接在命令行定义,因为是本地变量,所以在环境变量中是没有的。
      在这里插入图片描述
      通过set命令显示所有的环境变量和本地变量,所以我们确定12345添加导了本地变量中。
      在这里插入图片描述
      通过unset取消环境变量或者本地变量
      在这里插入图片描述

      为什么可以在命令行中定义环境变量?

      程序可以动态开辟空间,字符串占用空间是空间数据。

      ==
      进程是程序也可以动态开辟空间,环境变量作为字符串空间数据,放在空间中。
      (bash本身就是个进程,环境变量其实就是字符串)

    • export
      export 设置一个新的环境变量,通过这个指令可以将本地变量设置为环境变量。
      在这里插入图片描述

    再来看一个系统调用函数。

    • getenv()
      getenv依据name字符串在环境变量表中查找,找到返回指向环境变量的指针。(前面也说过环境变量本质就是字符串)
      在这里插入图片描述
      先看一个小程序,测试环境变量中的USER。

        1 #include <stdio.h>  
        2 #include <unistd.h>  
        3 #include <string.h>  
        4 #include <stdlib.h>  
        5                                                                                                                                                   
        6 #define USER "USER"                     
        7 int main()                              
        8 {                                       
        9     char* who = getenv(USER);//获取环境变量USER         
       10     if(strcmp(who, "yzh") == 0)        
       11     {                                   
       12         printf("user: %s\n", who);      
       13     }                                   
       14     else                                                                                                                                       
       15     {                                                                                                                                          
       16         printf("Permission denied\n");                                                                                                         
       17     }                                   
       18     return 0;                           
       19 }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

      在这里插入图片描述
      我们切回root然后运行程序,看到用户名不匹配了。
      在这里插入图片描述

      环境变量USER最大的意义,可以标识当前使用的Linux用户。
      其实环境变量USER,也参与了一些核实用户权限的实现。(比如用户访问其它用户的文件,通过USER来判断当前用户是否符合)

    • 子进程继承父进程
      我们再来看一个小程序

        1 #include <stdio.h>
        2 #include <unistd.h>
        3 #include <string.h>
        4 #include <stdlib.h>
        5 
        6 #define myval "HELLO"
        7 int main()
        8 {
        9     char* myenv = getenv(myval);
       10     if(NULL == myenv)
       11     {
       12         printf("%s, not found\n", myval);
       13         return 1;
       14     }
       15     else
       16     {
       17         printf("%s : %s", myval, myenv);                                                                                                        
       18     }
       19     return 0;
       20 }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      通过定义本地变量,然后运行程序,HELLO没有找到,这是对的。
      在这里插入图片描述
      将HELLO定义为环境变量,然后运行程序,找到,这也没问题。
      在这里插入图片描述

      看到结果后,我们来看一下问题。

      环境变量在bash中是可以直接查看的,这没问题,为什么在我们写的程序里也能查看呢?
      getenv()只是从环境中读取字符串,来获取对应环境变量的值的。我们的程序是如何会有环境变量的?

      其实bash本身是一个进程,我们写的程序是bash中的一个子进程,子进程继承父进程,这也就使得了环境变量具有全局属性。(使得适应不同应用场景,让bash为我们找指令、身份认证)。

    3、子进程如何继承环境变量的?

    从main函数开始说起,main函数其实也有参数,由父进程或是系统传的参。
    这些参数其实叫命令行参数

    int main(int argc, char* argv[], char* env[])
    {}
    
    • 1
    • 2
    • int argc和char* argv[]
    int main(int argc, char* argv[])
    {}
    
    • 1
    • 2

    用处:

    1. argc 是argv数组里指针的数量。
    2. argc是一个数组,里面有多个指向字符串的指针。

    通过一个简单的程序来看它的作用。

      1 #include <stdio.h>
      2                                                                                                                                                     
      3 int main(int argc, char* argv[])
      4 {
      5     int i = 0;
      6     for(i = 0; i < argc; ++i)
      7     {
      8         printf("argv[%d] -> %s\n", i, argv[i]);
      9     }
     10     return 0;
     11 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    argv数组其实就是用来接收程序名和选项的,argc用来计数,shell将这整个字符串进行拆分,操作系统进行传参。(比如" ./myprocess -1 -2 -3 -4 -5 " 这一串字符串,拆成"./myprocess",“-1”,“-2”…)
    其实和我们之前使用的ls -l,ls -l -a等一样,这种命令行参数的最大意义就是能够介绍命令行选项,让一个程序通过不同选项实现不同功能。

    • char* env[]
    int main(int argc, char* argv[], char* env[])
    {}
    
    • 1
    • 2

    其实如果你写了这三个参数,系统会为你传两张表,一个是命令行参数表,一个是环境变量表。
    没错,env就是一个一个环境变量的指针数组。
    稍稍修改上面的程序

        1 #include <stdio.h>
        2 
        3 int main(int argc, char* argv[], char* env[])
        4 {
        5     int i = 0;
        6     for(i = 0; env[i]; ++i)
        7     {
        8         printf("env[%d] -> %s\n", i, env[i]);                                                                                                     
        9     }
       10     return 0;
       11 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    打印的结果就是所有环境变量(这里截一部分)
    在这里插入图片描述

    拓展一下,不传参获取环境变量的方式
    通过第三方变量二级指针environ获取环境变量表。
    (有人可能不理解为什么是二级指针:环境变量表是一个数组,数组里面存放很多一级指针指向环境变量,environ指向数组,是存放一级指针的指针,所以是二级指针。)
    在这里插入图片描述

      1 #include <stdio.h>  
      2 #include <unistd.h>
      3 int main()
      4 {
      5     extern char** environ;                                                                                                                          
      6     for(int i = 0; environ[i]; ++i)  
      7     {                                      
      8         printf("%d:%s\n", i, environ[i]);  
      9     }                 
     10                       
     11     return 0;         
     12 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    结果也是打印所有环境变量(这里也是截取了一部分)


    总结:

    1. 查看环境变量的方式有三种,getenv(),命令行参数,第三方变量environ。
    2. 后面两个内容太多,具体变量也不好定位,所有其实还是getenv()用的多。

    4、测试其它环境变量

    环境变量具有全局性。

    • 环境变量HOME和~
      HOME是用来显示当前用户名所在路径

    在这里插入图片描述在这里插入图片描述
    在之前学cd命令的时候,有一个cd ~ 意思是到用户目录下。
    通过echo ~我们发现~的信息和$HOME是一样的。
    在这里插入图片描述

    本章完~

  • 相关阅读:
    一文解读如何应用 REST 对资源进行访问?
    Spring Boot中RedisTemplate的使用
    【Mybatis源码分析】插件机制和Pagehelper插件源码分析
    npm发布vue3自定义组件库--方法一
    Matlab中的导入类
    【设计模式】10分钟学懂UML类图
    MySQL面试题
    为什么c++支持函数重载,c语言不支持
    C++之类型转换
    VUE面试题总结2
  • 原文地址:https://blog.csdn.net/Ahaooooooo/article/details/128037431