linux进程——解析命令行参数——环境变量详解

        前言:本节内容还是linux进程, 主要讲解里面的环境变量——我们首先要知道的就是环境变量其实就是操作系统维护的一组kv值, 环境变量是系统提供的一组 变量名=变量值 形式的变量。不同的环境变量之间具有不同的用途, 并且具有全局属性。 本篇内容主要分为两个大板块——第一个大板块主要是具体举几个环境变量的例子、第二个大板块主要是讲解环境变量的概念与知识点。

        ps:本节内容适合了解进程PCB的友友进行观看

        

目录

PATH

HOME

SHELL

getnev

什么是环境变量

命令行参数

命令行参数里的环境变量

本地变量与内建命令


PATH

        我们以前说过, 指令的本质就是一个进程。 而且, 我们以前也说过, 我们自己写的程序必须加上./, 而指令不需要./——请问这是为什么呢?

        这是因为, 系统当中, 针对我们指令的搜索, 我们的系统会为它提供一个环境变量——PATH, 我们可以使用echo $PATH打印。 (注意, 这里的$符号不能去掉, 因为不加$就意味着echo会将PATH当作一个字符串进行打印。这个时候, 打印的内容里面包含一串串路径, 并且这些路径用“:”进行分割, 这里面的每一条路径都对应着我们的指令进行搜索的路径。如下图;

        也就是说, 我们的系统怎么知道我们都是用的指令在哪里寻找呢? 就是因为PATH, 当我们调用某个指令的时候, 系统会进入PATH显示的每一个路径里面一个一个进行查找。 没找到就继续下一个, 没找到就继续下一个。 而如果某个程序被放到这些路径下面, 那么系统默认就会找到(就比如我们使用的指令 就是放到这里面的), 而如果某个程序没有被放到这些路径下面, 系统默认就找不到, 就会返回commend no found。 而如果想要运行这个程序就要输入这个程序的相对路径(就比如我们运行我们自己写的程序, 就是使用./程序, 这就是相对路径)

        想要在环境变量的路径中添加路径怎么做呢?

        就是使用PATH=$PATH:新添路径——其实这里的等号后面的路径就相当于PATH的新路径, 如果等号后面的PATH不要了, 只要添加新的路径, 那么新路径就不是现在这样既有PATH原本的路径, 又有新添路径了, 而是只有一个新路径。 

        注意:此时所修改的环境变量是内存级的环境变量, 想要变回来只需要重新启动一下xshell。

        综上:PATH:linux系统指令的搜索路径。

        windows下面的同样有环境变量, 事实上, 当我们使用python、java这些解释型语言的时候, 都需要配置环境变量, 而windows下面的环境变量的修改方法如下:

HOME

如图我们登陆了普通用户, 并且可以使用pwd查看当前当前目录, 同时我们使用echo $HOME;

也可以看到当前的目录。 

一个用户默认登录的进入的是用户的家目录, 那么为什么会这样呢?

因为一个用户在登录时, 系统默认识别$HOME命令, 查看当前用户的家目录在哪里, 当我们登录的时候, 就默认执行了cd $HOME指令进入了用户的家目录下。

SHELL

$SHELL可以查看当前命令行用的是什么, 即, 当前shell用的是哪一个可执行程序。

其他的, 还有很多的环境变量, env指令可以查看当前自己的进程和bash进程从系统继承下来的所有环境变量


 

getnev

通过c语言, c++我们也可以通过getenv函数获取某个环境变量。 

那么环境变量在权限中的应用?

如何就是通过getnev获取当前用户, 获取用户后和root账户做对比, 根据if else语句判断是不是root账户, 并在if或者else代码块里面执行对应的动作。 通过这个, 我们就能更好的理解权限问题——对于一个文件或者某个指令的权限判断, 是拥有者, 还是所属组, 亦或者是其他人。

什么是环境变量

        关于什么是环境变量, 在前言中博主已经提到。 但是这里还要补充一点:环境变量其实是有一定的用途的, 比如当前用户的家目录在哪, 当前的用户是谁,指令的搜索路径是哪里, shell的可执行程序是哪个等等。 

        而要具体的理解环境变量, 需要先理解命令行参数。 下面我们先来理解一下命令行参数的概念

命令行参数

      对于main函数来说, 其实它是可以有参数的, 如下:

int main(int argc, char* argv[]){}

        这里面的argv是一个指针数组, argc代表argv的数组元素个数。 argv里面的元素个数由argc决定。

        这里可以使用一个循环, 将argv里面的元素全部打印出来:

        然后我们运行这个程序, 或者运行这个程序的时候加上一些选项, 就能看到打印出来的结果分别是这样的:


 

        ps:这里有一个题外的问题——main函数是第一个被系统调用的函数吗?——不重要, 友友们自行跳过即可。

        为了回答这个问题, 我们就要思考如果main函数是第一个被调用的函数, 那么它是不是就势必不能被传参? 而我们的main函数是有参数的; 而且我们从c语言也说过第一个被系统调用的函数其实是叫做starUp的函数, 这个函数真正的无参。

        回到上面的图中, 想要知道为什么我们输入的选项越多, 打印的内容就越多,就涉及到了bash的知识点——其实我们在bash上面输入任何指令, 本质上都是在输入字符串。 就比如我们上面输入./process-7-11.exe -a -b -c, 这个其实就是输入了一个"./process-7-11.exe -a -b -c"字符串而已。 而bash在进行命令行解释的时候会将这些字符串按照空格进行分割, 这些字符串分成一个新的字符串一起传给main函数作为形参, 也就产生了下面这种效果, 然后for循环再依次打印。

bash命令行为什么要这么做呢?

我们来看一个程序, 就能知道bash为什么会这么做了:

我们运行这个程序, 就可以得到如下结果:

对比我们使用ls加选项的时候:

        对比上面的两个选项, 我们是不是就能发现, 我们常用的指令, 为什么要打上选项?是不是就是因为指令加选项 本质上都是运行一个程序, 只是根据不同的选项, 走到了不同的else if里面, 然后执行了对应的功能模块。 这就是指令选项的本质, 这就是命令行参数。——也就是说, 命令行参数的一个重要功能就是为指令、工具等提供命令行选项的支持!!!

        而只要需要选项, 那么就要用到命令行参数, 所以要有命令行参数——即命令行参数的意义就是, 为了让我们使用程序的时候根据不同的选项, 执行不同的操作。

        我们使用ls --help就能查看ls的所有选项

        也就是相当于我们自己编写的程序, 加上了一个--help选项

        最后要补充一点的就是对于argv来说, 它的最后一个元素默认是NULL,也就是说我们在上面程序模拟的时候, 其实是不需要使用if判断, 如下图:

        现在来看一个叫做向量表的概念。 这个向量表其实就是上面的argv, 类似下图:

知道了这些东西以后, 那么, 这里就可以回归正题——>环境变量。

命令行参数里的环境变量

        我们学习命令行参数不是无理头的, 命令行参数和环境变量具有一定的关系,在哪呢?——请问, 有没有人规定命令行参数只有argc, argv? 没有, 也就是说, main的参数可能还有别的。 那么, main函数还真有一个别的参数, 这个参数就叫做int* env[], 这个env[]里面保存的是main当前进程的所有环境变量。 而且, 这个env[]的结构这里也可以提一下——就是向量表。 也就是说, main函数的参数里, 有两张核心向量表, 一张用来保存选项, 一张用来保存环境变量!!!

        下面是实验:

        运行后, 就可以发现和我们使用env指令一样

综上, 我们以后再看待运行程序的时候, 就可以这么考虑——》一定是有一个startIp直接或者间接调用了main函数, 并将两张向量表, 一个选项表, 一个环境变量表传给了main函数。 然后main函数再跑起来。

        那么这里就有了结论, 首先我们知道我们自己运行的这个程序是一个子进程, 而bash是一个父进程。 但是我们在bash下使用env的时候和我们在子进程下打印的环境变量是一样的。 ——这个结论就是——我们所运行的程序, 都是子进程, bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息, bash再在自己的上下文中构建一个环境变量表。 当我们的子进程需要的话, 就可以将环境变量信息给子进程一份。也就是说, 子进程会继承父进程交给他的所有环境变量!!!这就是为什么环境变量具有全局属性——因为他会在子进程中一个一个地完整的继承下去。

        但是这里有一个问题, 就是环境变量也是数据, 我们知道进程之间是独立的。 而如果一个子进程想要修改环境变量, 那么就一定不能够影响父进程的环境变量(写时拷贝)

        那么,我们如何验证这些环境变量可以一个一个的传承下去呢?

        在这里我们可以自己添加一个环境变量——这里的变量有两种, 一种是直接变量名=变量, 这个是本地变量。 另一种是export变量名=比那辆, 这个是环境变量。 我们需要使用后者。

        

        这样, 就可以看到我们的环境变量了!但是, 这个环境变量是我们在bash上面创建的, 那么要验证环境变量的全局性, 就要看一下我们的子进程中有没有这个环境变量。那么有没有呢?答案是有的, 如下图:

        取消环境变量使用unset环境变量:

本地变量与内建命令

set指令可以查看当前shell中所有变量, 包括本地变量和环境变量

本地变量不会被继承, 只会在bash中被使用。 创建本地变量的方式上面已经提到, 就是变量名=变量

我们如何验证本地变量不会被继承呢? 这里, 我们来写一个程序:

这个程序可以打印环境变量

我们可以使用set, 查看当前到当前具有这个本地变量, 但是我们使用子进程进行查看的时候, 查看不到!

然后, 当我们把本地变量改成环境变量的时候, 就能查看到了:

以上, 就说明了本地变量不能被继承.

        那么, 看第二个问题:

        既然MY_VALUE是一个本地变量, 那么它就不能被子进程继承, 我们也知道, bash里面的指令, 其实就是一个个bash的子进程, 问题是, 为什么图中的echo可以打印出MY_VALUE呢?

        那么, 没有错, echo不是一个bash的子进程。 这里就可以纠正之前的一个认知错误, 那就是——bash里面的指令, 不全都是bash的子进程。

        命令其实分为两种:一种是常规指令, 通过创建子进程完成。 

                                        一种是内建命令, 这种命令bash不回去创建子进程, 而是自己亲自执行(就相当于我们自己写的程序, 但是没有fork子进程, 或者说bash调用了自己写的或者系统提供的函数。)

        我们可以通过cd来理解这个内建命令的概念:这里我们自己实现一个cd命令, 这里需要用到系统调用接口——chdir(const char* path)

原因就是因为我们自己写的程序是bash创建的子进程。 而cd是bash自己调用的本身代码块。 两者本质不一样, 但是我们同样可以看到我们自己写的程序的工作目录——就是proc进程查看里面的工作目录。 代码如下, 两次睡眠是为了我们进行更好的观察。

如图是刚刚运行程序, 这个时候工作路径还没有发生变化:

下图就是工作路径没有发生变化的时候子进程工作路径:

工作路径变化!说明子进程工作路径变化只改变自己, 而cd是是父进程, 它改变工作路径, 就意味着我们的命令路径变了!!!

在系统里面, 有一个变量, 可以让我们不适用main参数就打印全部的环境变量——environ, 使用如下:

打印结果如下:

以上, 就是本节全部内容, 下面是本节笔记:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(雷达数据处理中的)跟踪算法(4) --- 基于数据集的目标跟踪实践

说明 本文作为跟踪系列的第4篇博文,在前面几篇博文[1][2][3]的基础上对所采集的实际数据(来自国防科技大学电子科学学院所主导发布的数据集[4])进行跟踪实践。读者在阅读本文前,建议先阅读本系列的前3篇博文。 Blog 20240724 博文第一次撰写 目录 说明…

【Linux】管道通信和 system V 通信

文章目录 一、进程通信原理(让不同进程看到同一份资源)二、管道通信2.1 管道原理及其特点2.1 匿名管道和命名管道 三、共享内存通信3.1 共享内存原理3.2 创建和关联共享内存3.3 去关联、ipc 指令和删除共享内存 四、消息队列和信号量(了解&am…

【Unity2D 2022:UI】无法拖拽TextMeshPro组件

在预制体Card上挂载了四个Text Mesh Pro组件,分别命名为Name、HP、ATK、Description。 将预制体Card挂载脚本CardDisplay用来在预制体上显示属性,并创建TextMeshPro对象来接收TextMeshPro组件。 using TMPro; using UnityEngine; using UnityEngine.UI;…

HCIP之PPP协议(PAP认证,CHAP认证)、GRE、MGRE综合实验

实验过程 一、IP配置 [r1]interface Serial 4/0/0 [r1-Serial4/0/0]ip ad 15.1.1.1 24 [r1]interface GigabitEthernet 0/0/0 [r1-GigabitEthernet0/0/0]ip ad 192.168.1.1 24 r2]interface Serial 4/0/0 [r2-Serial4/0/0]ip ad 25.1.1.2 24 [r2]interface GigabitEthernet 0/…

基于 HTML+ECharts 实现智慧交通数据可视化大屏(含源码)

构建智慧交通数据可视化大屏:基于 HTML 和 ECharts 的实现 随着城市化进程的加快,智慧交通系统已成为提升城市管理效率和居民生活质量的关键。通过数据可视化,交通管理部门可以实时监控交通流量、事故发生率、道路状况等关键指标,…

LabVIEW多种测试仪器集成控制系统

在现代工业生产与科研领域,对测试设备的需求日益增长。传统的手动操作测试不仅效率低下,而且易出错。本项目通过集成控制系统,实现了自动化控制,降低操作复杂度和错误率,提高生产和研究效率。 系统组成与硬件选择 系…

MSSQL注入前置知识

简述 Microsoft SQL server也叫SQL server / MSSQL,由微软推出的关系型数据库,默认端口1433 常见搭配C# / .net IISmssql mssql的数据库文件 数据文件(.mdf):主要的数据文件,包含数据表中的数据和对象信息…

Mongodb入门介绍

文章目录 1、Mongodb:NoSQL数据库,分布式的文档型数据库2、适合场景:3、不适合场景:4、概念5、总结 1、Mongodb:NoSQL数据库,分布式的文档型数据库 2、适合场景: 1、web网站数据存储&#xff…

鸿蒙 Navigation VS Router 对比

当前HarmonyOS支持两套路由机制(Navigation和Router),Navigation作为后续长期演进及推荐的路由选择方案,其与Router比较的优势如下: 易用性层面: Navigation天然具备标题、内容、回退按钮的功能联动&…

Springboot循环依赖的解决方式

Springboot循环依赖的解决方式 起因原因解决方案配置文件解决使用工具类获取bean还有一种我设想的方案 起因 今天重构代码时,发现之前的代码结构完全混乱,没有按照MVC分层思想去编写,很多业务逻辑写在了controller中,导致引用的很…

Java | Leetcode Java题解之第278题第一个错误的版本

题目&#xff1a; 题解&#xff1a; public class Solution extends VersionControl {public int firstBadVersion(int n) {int left 1, right n;while (left < right) { // 循环直至区间左右端点相同int mid left (right - left) / 2; // 防止计算时溢出if (isBadVers…

哪个邮箱最安全最好用啊

企业邮箱安全至关重要&#xff0c;需保护隐私、防财务损失、维护通信安全、避免纠纷&#xff0c;并维持业务连续性。哪个企业邮箱最安全好用呢&#xff1f;Zoho企业邮箱&#xff0c;采用加密技术、反垃圾邮件和病毒保护&#xff0c;支持多因素认证&#xff0c;确保数据安全合规…

【大师与bug里特】M_Studio《王国之梦》学习笔记

1️⃣ Object & object(✅) 之辨 《7.泛型事件框架〈余2min左右时〉》 不然inspector窗口的最后一行&#xff08;告诉我们订阅者是SceneLoadManager它身上挂了☝️ObjectEventListener用来监听这个事件 有多少个事件注册到这里来了都能够看到&#xff09;还是不会出现 加上…

开源邮箱套件介绍系列1:SOGo

项目网站&#xff1a;SOGo | Free Open Source Webmail 提示&#xff1a;如下内容大部分来自官方网站&#xff0c;通过AI智能翻译而来。 1. SOGo功能概述 SOGo提供了多种访问日历和消息数据的方式。您的用户可以使用网页浏览器、Microsoft Outlook、Mozilla Thunderbird、Ap…

create-vue源码学习之 gradient-string 渐变色打印

效果 在使用 create-vue 脚手架时&#xff0c;想实现如下的打印效果。 探究过程 翻到源码里看到这一行 没错&#xff0c;绿色部分就是告诉我们如何生成的。可以看到引入了 gradient-string 包 于是乎&#xff0c;我来试试 pnpm i gradient-string pnpm i --save-dev …

【IT人生系列二】第一次离职你下定了什么决心

本文承接【IT人生系列一】你的第一份工作激起了多少浪花 转眼间&#xff0c;博主已经在java这趟列车上漂流了18个月之久&#xff0c;再美的风景也会厌倦&#xff0c;我也不是那个初到上海充满干劲的少年&#xff0c;理想与现实的落差让我越发迷茫&#xff0c;我无数次想过放弃…

怎么在PPT插入视频?3个做PPT常用的使用技巧分享!

PPT技巧在日常办公中扮演着重要角色&#xff0c;ppt是一个开放的视觉呈现工具和载体&#xff0c;它支持在页面中插入各种内容媒介&#xff0c;包括文本、图片、视频、音频、矢量素材等&#xff0c;特别是当涉及到PPT插入视频时&#xff0c;它的作用就显得尤为突出。 不过说到p…

ASP.NET Web Api 使用 EF 6,DateTime 字段如何取数据库服务器当前时间

前言 在做数据库设计时&#xff0c;为了方便进行数据追踪&#xff0c;通常会有几个字段是每个表都有的&#xff0c;比如创建时间、创建人、更新时间、更新人、备注等&#xff0c;在存储这些时间时&#xff0c;要么存储 WEB 服务器的时间&#xff0c;要么存储数据库服务器的时间…

计算机三级嵌入式笔记(二)——嵌入式处理器

目录 考点1 嵌入式处理器的结构类型 考点2 嵌入式处理器简介 考点3 ARM处理器概述 考点4 处理器和处理器核 考点5 ARM 处理器的分类 考点6 经典 ARM 处理器 考点7 ARM Cortex 嵌入式处理器 考点8 ARM Cortex实时嵌入式处理器 考点9 ARM Cortex 应用处理器 考点10 AR…

Linux--Socket编程预备

目录 1. 理解源 IP 地址和目的 IP 地址 2.端口号 2.1端口号(port)是传输层协议的内容 2.2端口号范围划分 2.3理解 "端口号" 和 "进程 ID" 2.4理解 socket 3.传输层的典型代表 3.1认识 TCP 协议 3.2认识 UDP 协议 4. 网络字节序 5. socket 编程接…