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

环境: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.

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/3515.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学习系统编程No.10【文件描述符】

引言&#xff1a; 北京时间&#xff1a;2023/3/25&#xff0c;昨天摆烂一天&#xff0c;今天再次坐牢7小时&#xff0c;难受尽在不言中&#xff0c;并且对于笔试题&#xff0c;还是非常的困难&#xff0c;可能是我做题不够多&#xff0c;也可能是没有好好的总结之前做过的一些…

UE4/5 C++网络服务器编程纪录【零】--准备篇

前言之前利用业余时间重新复习UE4/5的C开发&#xff0c;闲来无事做了个基于独立服务器的多人在线&#xff08;目前限定客户数量是20人以内&#xff09;DEMO&#xff0c;核心功能在我之前发的B站视频里面有&#xff0c;战斗、动作、交互以及场景演示都有了&#xff0c;有朋友看了…

Spring容器实现原理-Spring的结构组成与核心类

Spring容器基本用法 bean是Spring中最核心的东西&#xff0c;因为Spring就像是个大水桶&#xff0c;而bean就像是容器中的水&#xff0c;水桶脱离了水便没有什么用处了&#xff0c;让我们先看看bean的定义&#xff1a; /*** ClassName MyTestBean* Author jiaxinxiao* Date 2…

2021全球开放数据应用创新大赛-法律咨询问答亚军方案

赛题分析 任务&#xff1a;给定用户问题&#xff0c;根据多个候选答案生成回复&#xff0c;属于文本生成任务。 问题信用逾期了&#xff0c;银行打电话骚扰我父母&#xff0c;改如何处理候选答案1. 按照约定还款 2.报警标准回复你好&#xff0c;这种情况只能按照约定还款&…

Python 练习 六

1、(最大数的出现)编写程序读取整数,找出它们中的最大值&#xff0c;然后计算它的出现次数。假设输入以数字0结束。假设你输入的是“352555 0";程序找出的最大数是5&#xff0c;而5的出现次数是4。(提示:维护两个变量max和 count。变量max存储的是当前最大数&#xff0c;而…

CentOS 7安装redis6.2.6(包括服务开机自启和开放端口)

CentOS 7安装redis6.2.61. 官网下载redis文件2. 校验安装依赖2.1 安装系统默认版本gcc2.2 升级gcc版本3. 解压编译安装4. 修改配置redis.conf4.2 设置密码4.3 绑定ip&#xff08;可选&#xff09;5. 启动redis服务并测试5.2 测试安装是否成功5.3 redis开机自启配置6.开放防火墙…

QT表格控件实例(Table Widget 、Table View)

欢迎小伙伴的点评✨✨&#xff0c;相互学习&#x1f680;&#x1f680;&#x1f680; 博主&#x1f9d1;&#x1f9d1; 本着开源的精神交流Qt开发的经验、将持续更新续章&#xff0c;为社区贡献博主自身的开源精神&#x1f469;‍&#x1f680; 文章目录前言一、图示实例二、列…

art 虚拟机相关

​​​​​​​虚拟机中对象锁实现分析 Android 库加载命名空间 https://source.android.google.cn/docs/core/architecture/vndk/linker-namespace Android共享库命名空间-CSDN博客 编译 prebuilts/clang/host/linux-x86/clang-r450784d/bin/llvm-addr2line -f -C -e…

项目文章 | 缓解高胆固醇血症 ,浒苔多糖如何相助?

文章标题&#xff1a;Polysaccharides from Enteromorpha prolifera alleviate hypercholesterolemia via modulating the gut microbiota and bile acid metabolism 发表期刊&#xff1a;Food & Function 影响因子&#xff1a;6.317 作者单位&#xff1a;福建医科大…

关于Docker逃逸

关于Docker逃逸 文章目录关于Docker逃逸前言一、判断是否为docker容器&#xff1f;二、privileged特权模式启动容器逃逸三、 Docker Remote API未授权访问逃逸四、危险挂载导致Docker逃逸五、危险挂载Docker Socket逃逸六、 挂载宿主机procfs逃逸七、脏牛漏洞来进行docker逃逸八…

蓝桥杯C/C++VIP试题每日一练之矩形面积交

💛作者主页:静Yu 🧡简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者 💛社区地址:前端知识交流社区 🧡博主的个人博客:静Yu的个人博客 🧡博主的个人笔记本:前端面试题 个人笔记本只记录前端领域的面试题目,项目总结,面试技…

Qt容器学习

Qt容器Qt容器主要优点就是在所有的平台上的运行都表现的一致,并且它们都是隐含共享的.Qt容器的另外一个主要特征就是易于使用的迭代器类,它们可以利用QDataStream变成数据流,而且他们通常可以使用执行文件中的代码量比相应的STL类中的要少&#xff0e;最后&#xff31;t/Embedd…

动态规划---线性dp和区间dp

动态规划(三) 目录动态规划(三)一&#xff1a;线性DP1.数字三角形1.1数字三角形题目1.2代码思路1.3代码实现(正序and倒序)2.最长上升子序列2.1最长上升子序列题目2.2代码思路2.3代码实现3.最长公共子序列3.1最长公共子序列题目3.2代码思路3.3代码实现4.石子合并4.1题目如下4.2代…

论文解读:Less is More: Learning Highlight Detection from Video Duration

引言 高亮检测有可能极大地简化视频浏览&#xff0c;但现有的方法往往受到昂贵的监督要求的影响&#xff0c;人类观众必须手动识别训练视频中的高亮部分。我们提出了一种可扩展的无监督解决方案&#xff0c;利用视频时长作为隐式监督信号。我们的关键见解是&#xff0c;来自较…

【lwIP(第三章)】内存管理

目录一、内存管理简介二、lwIP内存堆和内存池应用三、lwIP内存堆简介1. First Fit算法2. lwIP内存堆原理解析2.1 mem_init程序解析2.2 mem_malloc程序解析2.3 mem_free程序解析四、lwIP内存池简介1. 实现lwIP内存池的文件2. lwIP内存池函数2.1 memp_init()2.2 memp_malloc()2.3…

数据迁移工具

1.Kettle Kettle是一款国外开源的ETL工具,纯Java编写,绿色无需安装,数据抽取高效稳定 (数据迁移工具)。 Kettle 中有两种脚本文件,transformation 和 job,transformation 完成针对数据的基础转换,job 则完成整个工作流的控制。 Kettle 中文名称叫水壶,该项目的主程序…

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】

文章目录前言1、分布式情况下如何加锁2、具体实现过程3、测试3.1 一个服务按照多个端口同时启动3.2 使用jmeter进行压测前言 上一篇实现了单体应用下如何上锁,这一篇主要说明如何在分布式场景下上锁 上一篇地址:加锁 1、分布式情况下如何加锁 需要注意的点是: 在上锁和释放…

Android开发-Android UI与布局

01 Android UI 1.1 UI 用户界面(User Interface&#xff0c;简称 UI&#xff0c;亦称使用者界面)是系统和用户之间进行交互和信息交换的媒介&#xff0c;它实现信息的内部形式与人类可以接受形式之间的转换。软件设计可分为两个部分&#xff1a;编码设计与UI设计。 1.2 Andr…

【数据结构与算法】堆与堆排序

目录一.堆的实现1.堆的概念2.堆的代码实现二.堆排序的讲解一.堆的实现 1.堆的概念 堆是一种数据结构&#xff0c;首先它总是一颗完全二叉树(因为堆适合表示完全二叉树)&#xff0c;在逻辑上堆是一颗完全二叉树&#xff0c;真正实现上是使用数组来实现的。根据不同的规则(任意…

OpenMV快速上手 | OpenMV硬件版本概述及HelloWorld

文章目录一、OpenMV1. 什么是OpenMV2. OpenMV版本2.1. OpenMV1&#xff08;M4 V1&#xff09;2.2. OpemMV2&#xff08;M4 V2&#xff09;2.3. OpenMV3&#xff08;M7&#xff09;2.4. OpenMV4&#xff08;H7&#xff09;二、OpenMV开发环境搭建三、hello world1. 连接OpenMV2.…