当前位置: 首页 > news >正文

深入Linux系列之环境变量

深入Linux系列之环境变量

那么在之前的内容中,我们已经介绍了我们Linux进程的一些关键属性,例如进程编号以及进程状态和进程优先级,那么本篇文章接介绍Linux的环境变量这一知识点,那么废话不多说,我们进入环境变量的·讲解

1.引入

那么我们目前已经十分熟悉我们的Linux操作系统了,那么我们可以通过输入命令行的方式来与机器进行交互,在我之前的文章中我也介绍过,那么我们在终端输入的这一行一行的指令,那么这些指令的本质其实是在某个特定路径下的可执行文件,那么我们命令行解释器的工作则是首先获取用户键盘输入的指令,然后将其解析分为指令部分与参数部分,然后到特定的路径下去进行寻找匹配我们指令所对应的可执行文件,然后用fork系统调用函数来创建一个子进程来执行我们指令所对应的可执行文件。

想必我们刚才上文所说的我们指令的执行过程你已经很熟悉了,但是我们回看我们指令执行的过程,我们也许会有一个疑惑的点,那就是当我们用户输入一行指令的时候,那么我们命令行解释器获取完指令回到特定的路径下去搜索匹配,那么这里我们可能会产生一个疑问,那么就是我们用户自己输入的各个不同的指令,命令行解释器怎么知道该指令所对应的可执行文件具体在哪个位置,以及它究竟该在哪里去进行搜索?那么我们知道这些指令所对应的可执行文件是存放在我们的系统的特定路径下,也就是配置文件目录下,那么我们命令行解释器如果能够成功搜索匹配到对应的可执行文件,那么它一定得记住我们这些指令所在的可执行文件可能会出现在哪些位置,然后就到这些路径下依次去搜索就可以了。

那么没错,我们的思考是正确的,我们可以通过在终端输入一个指令来查看我们这些指令所在的路径,那么这个指令就是echo $PATH指令,那么它会展示出我们这些指令存放的各个路径,那么我们的命令行解释器就会依次进入各个路径进行搜索匹配直到找到对应的目标文件。
在这里插入图片描述

那么我们知道我们命令行解释器之所以能够获取到我们输入指令所在的可执行文件,会因为它本身有我们这些指令保存的各个不同的路径,从而只需要到这些路径中去依次进行搜索匹配即可,所以这就解释了,我们如果在终端自己随便输入一个不存在的指令,那么当命令行解释器搜寻完所有的配置文件之后,都查不到我们该指令的内容,那么它就会在终端打印我们的command not found,所以今天我们弄清楚命令行解释器执行我们指令的原理之后,我们知道它手上是有一个指令可能出现的所有位置的记录,那么我们如果要自己自定义一个指令,比如我们用c语言编写了一个mycommand的可执行文件,那么如果我们要想达到输入mycommand,那么我们的命令行解释器能够执行我们编译好的mycommand的可执行文件,那么我们就有两种策略:

第一种是我们将我们该可执行文件放到系统的配置文件目录中,因为我们知道我们命令行解释器会到这些路径下搜索,一旦找到,那么就会创建一个子进程来进行执行

第二种就是我们将我们该可执行文件所在的目录添加到我们的命令行解释器要进行指令的搜索路径当中,那么它也会从该目录下找到我们该文件然后执行,但是需要我们输入指令来export PATH=$PATH:/home/path添加。
在这里插入图片描述

2.环境变量

那么刚才所介绍这个指令的搜索路径我们这个信息也只是在我们环境变量中的冰山一角,那么铺垫了这么久,我们来正式介绍我们的环境变量,那么我们先回答我们环境变量是什么:

那么我们环境变量则是记录了我们当前进程的运行环境的信息。

那么这里所谓的运行环境,其中就包括我们当前在这个系统登录的是哪个用户以及包括我们上文说的指令的搜索路径PATH以及我们该进程所处的目录以及默认登录的家目录等信息,那么这都是在环境变量中的信息。

那么看到这,你可能会有一个疑问,那么就是我们记录一个进程的环境变量,那么至于记录这么多信息吗,那么我们进程运行不就操作系统对该进程创建一个task_struct结构体然后把它的内核数据加载到内存不就可以了吗,需要用到这么多信息吗?

那么对此我想说的是,环境变量之所以设计这些肯定有它的道理,比如我们环境变量会有当前登录的用户的信息,你看似这个好像跟进程的运行没有关系,但是我们知道我们在Linux操作系统有权限的问题,那么假如我们在我们该进程的代码里有向其他文件进行读取或者写入的操作,那么我们能不能进行读取或者写入,那么这就和用户所具有的权限有关,那么我们需要知道用户是谁以及对应的身份才能允许确定能不能执行该操作,所以我们要知道进程中没有用到某些环境变量里面的内容不代表它没有用。

那么我们了解到环境变量就是记录了进程运行有关的运行环境信息,那么我们可以用我们的env指令来查看我们的环境变量
在这里插入图片描述

那么知道了环境变量的概念之后,那么我们再来谈一下环境变量的特征,那么环境变量的第一个特征就是全局性,那么为什么这么说呢,那么我们知道我们没创建一个进程,那么我们该进程都会有一份对应的task_struct结构体以及对应的一份环境变量,那么我们task_struct结构体的也有一个字段envp来保存环境变量的地址。

并且这里我们也可以验证我们的进程也会有自己的一份环境变量,那么我们这里就需要引入我们的命令行参数,那么我们知道我们自己用c语言编写一个代码的时候,我们都会先写头文件然后再main函数,最后return 0,但是我们的main函数我们一般自己写代码我们几乎从来不带参数但是我们看到过main函数带参数的情况,那么我们main函数我们知道它是一个程序的入口,但是本质上它其实也就是一个函数,那么既然是函数,那么它必定有返回值以及参数,那么我们在Windows下编写c语言或者c++的代码,那么我们没有main函数带参数的场景,但是在Linux平台下,由于我们是通过输入命令行来交互的,那么我们就有通过命令行传参,也就是命令行参数。

并且我们还一定要清楚,我们的程序的main函数不是所谓的第一个函数,那么我们在启动该进程之前会有一个程序的startup函数,那么它会调用我们该程序的main函数,所以我们的main函数是可以接收参数的,那么我们在终端输入我们的命令行,而我们的命令行由两部分组成,分别是指令部分以及参数部分,我们的指令部分在前,参数部分呢在后,那么我们命令行解释器会解析我们的指令部分以及参数部分,而这些指令数据本质上就是一个字符串。

那么我们main函数的参数列表有两种,第一种就是int main(int argc,char* argv[])
在这里插入图片描述
在这里插入图片描述

那么第一个参数就是指令的个数包括指令部分以及参数部分,比如ls -l,会被解析为“ls”和“-l”两部分,那么指令个数就是2,argc就是2,然后我们这两个字符串就会被保存到我们的指针数组里,也称之为参数列表里,那么我们当用c语言编写好一个mycode的函数,那么意味着我们可以向mycode进程传参,那么我们接下来也可以编写一个c语言代码来验证一下:

那么如图可以看到结果,但是这还跟我们想要看到的环境变量还没有联系,那么刚才只是铺垫,那么我们的main函数的参数列表除了刚才的那种形式,在我们的Linux平台还有第二种形式:

int main(int argc ,char* argv[],char* env[])

也就是说还有第三个参数,那么这第三个参数也是一个指针数组,那么看这个指针数组的名字你也知道了,那么这个指针数组就是我们的环境变量,那么没错我们不仅可以向我们的main函数传递我们的命令行参数还可以传递我们的环境变量,那么我们这个env函数的最后一个元素是以NULL结尾的,那么我们可以遍历我们的env数组来查看我们该进程的环境变量了,并且我们还可以有系统调用接口,getenv函数来得到特定属性的环境变量
在这里插入图片描述

那么这个char* env的存在就证明了,我们每一个进程都有自己的环境变量,而我们进程具体是怎么得到自己的环境变量,那么我们知道我们可以通过命令行传参的方式得到。

但是我们发现我们自己在Linux平台上自己写代码,我们的main函数是不加任何参数,那么我们运行这个程序也就相当于创建了一个进程,但是我们创建了一个进程也就意味着创建了对应的一份task_struct结构体以及自己的对应的一份环境变量,那么我们这里没有定义参数,那么我们这里进程是怎么生成自己一份的环境变量呢?

那么我们子进程的环境变量是继承于我们父进程的,并且修改了其中的部分属性,就像我们用fork函数创建子进程一样,那么我们子进程的task_struct结构体也是直接拷贝一份父进程的task_struct结构体然后修改其中的部分属性包括进程编号以及状态等,所以我们不必直接传参,那么在我们操作系统内核会帮组我们再创建子进程的时候,拷贝我们父进程的环境变量并且修改部分属性,所以我们说我们的环境变量具有全局性。

3.结语

那么这就是本篇关于环境变量的全部内容了,那么本篇文章围绕着环境变量讲述了环境变量是什么,有什么用,以及一些相关的指令,那么我的下一篇文章将是讲解我们的进程地址空间,我会持续更新,希望你能多多关注,希望本篇文章能够让你有所收获。
在这里插入图片描述

相关文章:

深入Linux系列之环境变量

深入Linux系列之环境变量 那么在之前的内容中,我们已经介绍了我们Linux进程的一些关键属性,例如进程编号以及进程状态和进程优先级,那么本篇文章接介绍Linux的环境变量这一知识点,那么废话不多说,我们进入环境变量的讲…...

国产编辑器EverEdit - Web预览功能

1 Web预览 1.1 应用场景 在编辑HTML文件时,可以通过EverEdit的Web预览功能,方便用户随时观察和调整HTML代码。 1.2 使用方法 1.2.1 使用EverEdit内部浏览器预览 选择主菜单查看 -> Web预览,或使用快捷键Ctrl B,即可打开Ev…...

C#中的Frm_Welcome.Instance.Show(),是什么意思

Frm_Welcome.Instance.Show() 是一种常见的单例模式(Singleton Pattern)实现方式,通常用于在应用程序中确保某个窗体(Form)只有一个实例,并通过该实例显示窗体。以下是对这段代码的详细解释: 代…...

07苍穹外卖之redis缓存商品、购物车(redis案例缓存实现)

课程内容 缓存菜品 缓存套餐 添加购物车 查看购物车 清空购物车 功能实现:缓存商品、购物车 效果图: 1. 缓存菜品 1.1 问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压…...

C++开发(软件开发)常见面试题

目录 1、C里指针和数组的区别 2、C中空指针请使用nullptr不要使用NULL 3、http/https区别和头部结构? 4、有了mac地址为什么还要ip地址?ip地址的作用 5、有了路由器为什么还要交换机? 6、面向对象三大特性 7、友元函数 8、大端小端 …...

人工智能-A*算法与卷积神经网络(CNN)结合实现路径规划

以下是一个将 A* 算法与卷积神经网络(CNN)结合实现路径规划的代码示例。主要思路是使用 A* 算法生成训练数据,然后用这些数据训练一个 CNN 模型,让 CNN 学习如何预测路径,最后使用训练好的 CNN 模型进行路径规划。 代码实现 import numpy as np import heapq import tor…...

蓝桥杯备赛——进制转化相关问题

目录 一、基础概念 二、问题研究(1) 代码解读: 1. transfer 函数 代码功能概述 详细步骤 2. main 函数 代码功能概述 详细步骤 三、运用递归解决 (一) 代码如下: 代码解读: &#…...

DevOps的个人学习

一、DevOps介绍 软件开发最初是由两个团队组成: 开发团队:负责设计和构建系统。运维团队:负责测试代码后部署上线,确保系统稳定安全运行。 这两个看似目标不同的团队需要协同完成一个软件的开发。DevOps整合了开发与运维团队&a…...

使用Pytorch训练一个图像分类器

一、准备数据集 一般来说,当你不得不与图像、文本或者视频资料打交道时,会选择使用python的标准库将原始数据加载转化成numpy数组,甚至可以继续转换成torch.*Tensor。 对图片而言,可以使用Pillow库和OpenCV库对视频而言&#xf…...

《ARM64体系结构编程与实践》学习笔记(四)

MMU内存管理 1.MMU内存管理(armv8.6手册的D5章节),MMU包含快表TLB,TLB是对页表的部分缓存,页表是存放在内存里面的。 AArch64仅仅支持Long Descriptor的页表格式,AArch32支持两种页表格式Armv7-A Short De…...

01-SDRAM控制器的设计——案例总概述

本教程重点▷▷▷ 存储器简介。 介绍 SDRAM 的工作原理。 详细讲解SDRAM 控制的Verilog 实现方法。 PLL IP和FIFO IP 的调用,计数器设计,按键边沿捕获,数码管控制。 完成SDRAM控制器应用的完整案例。 Signal Tap 调试方法。 准备工作▷…...

京准:NTP卫星时钟服务器对于DeepSeek安全的重要性

京准:NTP卫星时钟服务器对于DeepSeek安全的重要性 京准:NTP卫星时钟服务器对于DeepSeek安全的重要性 在网络安全领域,分布式拒绝服务(DDoS)攻击一直是企业和网络服务商面临的重大威胁之一。随着攻击技术的不断演化…...

uniapp访问django目录中的图片和视频,2025[最新]中间件访问方式

新建中间件, middleware.py 匹配,以/cover_image/ 开头的图片 匹配以/episode_video/ 开头的视频 imageSrc: http://192.168.110.148:8000/cover_image/12345/1738760890657_mmexport1738154397386.jpg, videoSrc: http://192.168.110.148:8000/episode_video/12345/compres…...

RuoYi-Vue-Oracle的oracle driver驱动配置问题ojdbc8-12.2.0.1.jar的解决

RuoYi-Vue-Oracle的oracle driver驱动配置问题ojdbc8-12.2.0.1.jar的解决 1、报错情况 下载:https://gitcode.com/yangzongzhuan/RuoYi-Vue-Oracle 用idea打开,启动: 日志有报错: 点右侧m图标,maven有以下报误 &…...

python脚本实现windows电脑内存监控内存清理(类似rammap清空工作集功能)

import ctypes import psutil import time import sys import os from datetime import datetime import pyautogui# 检查管理员权限 def is_admin():try:return ctypes.windll.shell32.IsUserAnAdmin()except:return False# 内存清理核心功能 def cleanup_memory(aggressivene…...

【狂热算法篇】并查集:探秘图论中的 “连通神器”,解锁动态连通性的神秘力量

嘿,朋友们!喜欢这个并查集的讲解吗 记得点个关注哦,让我们一起探索算法的奥秘,别忘了一键三连,你的支持是我最大的动力! 欢迎拜访:羑悻的小杀马特.-CSDN博客 本篇主题:深度剖析并查…...

SpringBoot中实现动态数据源切换

SpringBoot中实现动态数据源切换 文章目录 SpringBoot中实现动态数据源切换SpringBoot中实现动态数据源切换基础知识1. 什么是数据源?2. 动态数据源切换的概念3. Spring Boot 中的默认数据源配置4. 动态数据源的挑战5. Spring 中的数据源切换方式 设计思路1. 明确应…...

数据结构及排序算法

数据结构 线性结构 ◆线性结构:每个元素最多只有一个出度和一个入度,表现为一条线状。线性表按存储方式分为顺序表和链表。 存储结构: ◆顺序存储:用一组地址连续的存储单元依次存储线性表中的数据元素,使得逻辑上相邻的元素物理上也相邻。 ◆链式存储:存储各数据元素的结点…...

Python基础-元组tuple的学习

在 Python 中,元组(tuple)是一种不可变的序列类型,允许存储不同类型的元素。元组非常类似于列表(list),但与列表不同的是,元组一旦创建,就不能修改其内容。 1 元组的创建…...

【手写公式识别】MEMix: Improving HMER with Diverse Formula Structure Augmentation 论文阅读

发表于:ICME 2024 原文链接:https://ieeexplore.ieee.org/document/10687521 源码:无 Abstract 手写数学表达式识别(HMER)旨在将数学表达式(MEs)的图像转换为相应的LaTeX序列。然而&#xff0…...

使用deepseek写一个飞机大战游戏

说明: 安装pygame:在运行代码之前,需要先安装 pygame 库。可以通过以下命令安装: pip install pygame图像文件:需要将玩家、敌人和子弹的图像文件(player.png, enemy.png, bullet.png)放在与脚本…...

用Kibana实现Elasticsearch索引的增删改查:实战指南

在大数据时代,Elasticsearch(简称 ES)和 Kibana 作为强大的数据搜索与可视化工具,受到了众多开发者的青睐。Kibana 提供了一个直观的界面,可以方便地对 Elasticsearch 中的数据进行操作。本文将详细介绍如何使用 Kiban…...

C# 封送和远程编程介绍

.NET学习资料 .NET学习资料 .NET学习资料 在 C# 编程领域中,封送(Marshaling)和远程编程(Remote Programming)是两个极为重要的概念,它们为开发者提供了与不同环境、不同进程或不同机器上的代码进行交互的…...

MybatisPlus较全常用复杂查询引例(limit、orderby、groupby、having、like...)

MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。以下是 MyBatis-Plus 中常用复杂查询(如 LIMIT、ORDER BY、GROUP BY、HAVING、LIKE 等)的引例: 1. 环境准备…...

02.07 TCP服务器与客户端的搭建

一.思维导图 二.使用动态协议包实现服务器与客户端 1. 协议包的结构定义 首先,是协议包的结构定义。在两段代码中,pack_t结构体都被用来表示协议包: typedef struct Pack {int size; // 记录整个协议包的实际大小enum Type type; …...

Jenkins数据备份到windows FTP服务器

文章目录 背景1. 安装配置 FileZilla Server(Windows)1.1 下载并安装 FileZilla Server1.2 配置 FTP 用户和共享目录 2. 安装并配置 FTP 客户端(CentOS)2.1 在 CentOS 安装 lftp 3. 编写 Jenkins 备份脚本3.1 赋予执行权限3.2 测试…...

【R语言】卡方检验

一、定义 卡方检验是用来检验样本观测次数与理论或总体次数之间差异性的推断性统计方法,其原理是比较观测值与理论值之间的差异。两者之间的差异越小,检验的结果越不容易达到显著水平;反之,检验结果越可能达到显著水平。 二、用…...

ASP.NET Core托管服务

目录 托管服务的异常问题 托管服务中使用DI 托管服务案例:数据的定时导出 场景,代码运行在后台。比如服务器启动的时候在后台预先加载数据到缓存,每天凌晨3点把数据导出到备份数据库,每隔5秒钟在两张表之间同步一次数据。托管服…...

HarmonyOS 5.0应用开发——全局自定义弹出框openCustomDialog

【高心星出品】 文章目录 全局自定义弹出框openCustomDialog案例开发步骤完整代码 全局自定义弹出框openCustomDialog CustomDialog是自定义弹出框,可用于广告、中奖、警告、软件更新等与用户交互响应操作。开发者可以通过CustomDialogController类显示自定义弹出框…...

如何在C++ QT 程序中集成cef3开源浏览器组件去显示网页?

文章目录 1. **准备工作**1.1 下载CEF31.2 配置Qt项目2. **集成CEF3到Qt窗口**2.1 创建Qt窗口容器2.2 初始化CEF33. **处理CEF3消息循环**4. **处理多进程架构**5. **完整代码示例**`main.cpp`6. **常见问题**6.1 黑屏问题6.2 窗口嵌入失败6.3 多进程调试7.**Github源码参考**8…...