【Linux】进程理解与学习Ⅲ-环境变量

简介: 【Linux】进程理解与学习Ⅲ-环境变量

前言



什么是变量?


在学习之前我们要先搞清楚这个概念,就比如说【y=ab+cd】,在这里,等号左边的就是变量,等号右边的则是变量的内容。变量是bash中非常重要的一个存在,在Linux下变量又分为自定义变量以及环境变量。本次章节讲对此做相关理解。


变量的定义与查看

变量的定义与查看


由我们用户自己来直接定义的变量叫做自定义变量(也可以说时本地变量),上面说过等号左边为变量名,右边为变量的内容,我们便可以根据此特点直接定义一个自定义变量。(我们可以通过echo $变量名来查看该变量的内容)如下:


1.png


★注意点:


这里我们在定义变量时,有以下几点需要注意:


等号两边不能直接跟空格,否则会报错


等号左边的变量名的开头只能是英文字母(比如:2myval这种写法错误)


假如我们想要保持一个变量的内容,并用该变量名去定义另一个变量时,我们要在该变量名称前加上$符号(比如我用myval的内容去定义age,就要写成age=$myval.其中$的作用便是保留原有变量的内容,记住这一点,后面配置PATH中会用到此特点)


在定义变量时,前面加export,就会将该变量导入环境变量表中(环境变量后面会讲)


2.png


变量的取消定义


我们可以使用unset 变量名的指令来取消该变量的定义,如下:


3.png


环境变量



什么是环境变量呢?相信学习Java、Python的老铁们应该会有一个更深刻的认识,因为在写Java之前,相信大家都会安装jdk,并在Windows下配置相关环境变量,配置完成后才能正常编写。如下图所示,这就是Windows下的环境变量:


4.png


Windows下的环境变量


说了这么多,还是没说到环境变量究竟是什么?


实际上环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。Linux中同样也存在着相关的环境变量。


这里举个例子:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

不仅如此,环境变量通常还具有全局属性,并且一般都是以大写字符来表示。而由各个环境变量在一起构成的集合,一般我们称之为环境变量表,环境变量表可以被子进程继承。(先说结论)


常见环境变量


以上所讲都只是一些概念层次的知识,接下来我们讲几个比较常见的环境变量,以便于大家能更好的理解。


PATH : 指定命令的搜索路径


SHELL : 当前Shell,它的值通常是/bin/bash。


USER:当前用户


PATH

我们在写完代码并编译,生成一个可执行程序时,为什么运行的时候要加./?实际上运行一个程序的前提是找到该程序。只有找到它,才能运行它,而./的含义大家应该知道,表示的是当前所在路径。


5.png


那么为什么我们输入ls的时候,则不用指定ls所在的具体位置呢?这里就涉及到了PATH,我们可以输入指令echo $PATH来查看PATH这个环境变量的内容,并且输入指令which ls:来查看ls所在的路径。就会发现原来ls所在的路径在PATH里。


6.png


而PATH的作用则是指定搜索路径,所以我们输入指令ls的时候,会自动去PATH中搜寻路径,发现PATH中有ls所在的路径,因此我们直接输入ls的时候,不用我们手动指定路径,也可以运行ls。但是如果我们不手动指定我们自己写的程序mytest,则会报错,因为环境变量中并没有mytest所在的路径。


7.png


那么我们可不可以像Windows一样,配置我们的环境变量呢?答案是可以的。


PATH环境变量的配置

我们可以使用指令export PATH=$PATH:自定义路径(上面在变量的定义中讲了$的作用就是保留PATH的原有内容,PATH中:是分隔符,所以我们这样来定义就相当于给PATH追加了一个内容。)如下:


8.png


环境变量的查看


一、env指令


我们可以直接输入指令env,便可以查看当前bash下的所有环境变量


9.png


二、通过指针数组访问


实际上,我们的环境变量表是一个指针数组结构,而环境变量会被子进程所继承。我们便可以利用此特点来使用我们自己写的函数打印出环境变量。其实我们在写main函数时,实际上main函数有三个参数:int argc、char* argv[]、char*envp[]。而char*envp[]这个指针数组中的内容,就指向我们所说的环境变量表的内容的起始地址。如下:


10.png


我们可以通过代码来验证一下:


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


11.png


运行结果


三、通过全局变量environ获取


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

四、通过系统调用函数getenv()来获取我们想要的环境变量


我们可以通过系统调用函数getenv()来获取我们想要查看的环境变量,如下:


#include<stdio.h>
#include<stdlib.h>//头文件
 int main()
 {
   printf("%s",getenv("PATH"));
 }


关于环境变量的理解


先来看以下代码:


12.png


我们从中可以得出结论:


只有环境变量会被子进程所继承,自定义变量并不会。自定义变量只能在自己的shell内使用。实际上在环境变量的查看中我们也验证了这一点:即main函数实际上的第三个参数,便是用来接收环境变量表的指针数组。


13.png


★总结



上面讲的有些零碎,这里做一个总结:


【y=a】等号左边表示的是变量名,右边表示变量内容


我们可以通过echo $变量名的指令,来查看该变量的内容


在定义变量时,前面加上export,则会将该变量导入环境变量表


环境变量表实际上是所有环境变量的集合,本质上是一个指针数组,每一个数组元素都是指针,指向对应的环境变量的内容的起始位置。(最后一个位置为NULL)


set指令会打印出所有的变量的内容(本地、环境),env则只打印环境变量的内容


环境变量我们可以通过main函数中的指针数组来查看(环境变量会被子进程继承,所以我们写的程序也可以拿到父进程bash的环境变量表)、也可以通过全局变量environ来查看,或者通过函数getenv()来获取。


环境变量可以被所有子进程继承,但是自定义变量则只可以在自己的shell中使用。


我们可以通过unset 环境变量名 来取消该环境变量。


环境变量实际上是内存级别的一张表,当我们登录系统时,os会给用户形成特定的环境变量表。而环境变量对应的数据实际上保存在了系统的相关配置文件中(bashrc、profile等)。


14.png


环境变量的相关配置文件部分内容


命令行参数



在上面我们讲到了main函数中的三个参数,为int argc、char* argv[]、char* envp[]。其中我们了解了第三个参数,也就是用来接收环境变量表的指针数组。那么前面两个呢?


argc:传入的元素个数(也就是我们输入的指令的个数)


char* argv[]:也是一个表,只不过这张表存放的是指向传入的元素的起始位置的指针。其中,最后一个有效元素的下一个内容为NULL(这张表由bash制作)


15.png


当然,我们也可以写以下代码来验证:


#include<stdio.h>
 //argc:传入的元素个数                                                                                                    
 //argv:用来存放元素内容起始位置的指针数组
 int main(int argc,char* argv[])          
 {                                        
   printf("传入的元素个数为:%d\n",argc);
   printf("传入的有效元素内容为:\n");  
   for(int i=0; i<argc; i++)          
   {                        
     printf("argv[%d]:%s\n",i,argv[i]);
   }                                   
   return 0;                           
 }


16.png


运行结果


为什么我们输入ls -a 与ls -l 的功能不同,原理也在于此,即对命令行参数进行相关指令设置。我们也可以实现一个简单的任务:如下:


#include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 #include<unistd.h>
 void Utest(char* st)
 {
   printf("%s:-[a | b]\n",st);
 }
 int main(int argc,char* argv[])
 {
   //身份验证,只有qidunyan用户可以进行操作
   if(strcmp(getenv("USER"),"qidunyan"))
   {
     printf("%s用户非法\n",getenv("USER"));
     return 0;
   }
   //指令输入错误                                                                                                                             
   if(argc!=2)
   {
     printf("指令错误,请重新输入:\n");
     Utest(argv[0]);
   }
// ./mytest -a
   if(strcmp(argv[1],"-a")==0)
   {
     printf("执行A任务\n");
     //...
     sleep(3);
     printf("执行完毕\n");
   }                                                                                                                                          
   else if(strcmp(argv[1],"-b") == 0)
   {
     printf("执行B任务\n");
     //...
     sleep(3);
     printf("执行完毕\n");
   }
   else 
   {
     printf("指令错误,重新输入:\n");
     Utest(argv[0]);
   }
 return 0;
 }


17.png


运行结果


相关文章
|
24天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
55 1
|
1月前
|
Linux 编译器 开发工具
【Linux快速入门(三)】Linux与ROS学习之编译基础(Cmake编译)
【Linux快速入门(三)】Linux与ROS学习之编译基础(Cmake编译)
|
12天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
68 13
|
19天前
|
SQL 运维 监控
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
|
27天前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
1月前
|
缓存 算法 Linux
Linux内核的心脏:深入理解进程调度器
本文探讨了Linux操作系统中至关重要的组成部分——进程调度器。通过分析其工作原理、调度算法以及在不同场景下的表现,揭示它是如何高效管理CPU资源,确保系统响应性和公平性的。本文旨在为读者提供一个清晰的视图,了解在多任务环境下,Linux是如何智能地分配处理器时间给各个进程的。
|
1月前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
87 8
|
1月前
|
存储 运维 Linux
如何在 Linux 系统中使用 envsubst 命令替换环境变量?
`envsubst` 是 Linux 系统中用于替换文本中环境变量值的实用工具。本文分三部分介绍其工作原理、使用方法及实际应用,包括配置文件替换、脚本执行中环境变量替换和动态生成文件等场景,帮助用户高效利用 `envsubst` 进行开发和运维工作。
68 4
|
1月前
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
108 1
|
1月前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?