草庐IT

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

诺诺的包包 2023-06-21 原文
环境:centos7.6,腾讯云服务器
Linux文章都放在了专栏:【 Linux 】欢迎支持订阅 🌹
相关文章推荐:
【Linux】冯.诺依曼体系结构与操作系统

【Linux】进程理解与学习Ⅰ-进程概念

浅谈Linux下的shell--BASH

【Linux】进程理解与学习Ⅱ-进程状态

前言

什么是变量?

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

变量的定义与查看

  • 变量的定义与查看

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

★注意点:

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

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

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

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

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

  • 变量的取消定义

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

环境变量

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

Windows下的环境变量

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

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

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

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

常见环境变量

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

  • PATH : 指定命令的搜索路径

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

  • USER:当前用户

PATH

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

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

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

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

PATH环境变量的配置

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

环境变量的查看

  • 一、env指令

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

  • 二、通过指针数组访问

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

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

 #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]);
   }                                   
 } 

运行结果

  • 三、通过全局变量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"));
 }

关于环境变量的理解

先来看以下代码:

我们从中可以得出结论:

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

★总结

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

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

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

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

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

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

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

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

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

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

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

命令行参数

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

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

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

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

#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;                           
 }  

运行结果

为什么我们输入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;
 }

运行结果


end.

生活原本沉闷,但跑起来就会有风!🌹

有关【Linux】进程理解与学习Ⅲ-环境变量的更多相关文章

  1. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  2. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  3. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  4. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  5. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  6. ruby-on-rails - 使用 ruby​​ 将多个实例变量转换为散列的更好方法? - 2

    我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。

  7. ruby - Rack:如何将 URL 存储为变量? - 2

    我正在编写一个简单的静态Rack应用程序。查看下面的config.ru代码:useRack::Static,:urls=>["/elements","/img","/pages","/users","/css","/js"],:root=>"archive"map'/'dorunProc.new{|env|[200,{'Content-Type'=>'text/html','Cache-Control'=>'public,max-age=6400'},File.open('archive/splash.html',File::RDONLY)]}endmap'/pages/search.

  8. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

    之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

  9. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  10. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

随机推荐