前引提到 Linux 环境变量很多新手都会觉得它高深莫测仿佛是一道难以跨越的技术门槛。实际上环境变量并非遥不可及它就存在于我们日常的 Linux 操作中比如执行echo $PATH查看路径或是配置 JDK 时设置JAVA_HOME。了解环境变量不仅能帮助我们更好地理解 Linux 系统的运行逻辑还能让我们根据自身需求自定义系统环境提升操作便利性。本文将用通俗易懂的语言带你走进 Linux 环境变量的世界从它的基本作用、常见分类讲起逐步教你掌握自定义配置的实用技巧让你彻底告别对环境变量的 “陌生感”重点【九】究极逻辑详解与逻辑图目录【一】环境变量介绍【二】常见的环境变量名【三】环境变量分类【四】环境变量添加【五】环境变量查看【六】命令行参数1argc与argv2env【七】进程的启动【八】进程地址空间1前引2原理讲解3创建子进程4页表【九】究极逻辑详解【一】环境变量介绍环境变量是 Linux 系统中 “存储全局信息的变量”供所有程序 / 命令调用帮它们快速找到需要的资源避免重复配置即记录各种资源路径位置的变量场景我们执行各种指令它需要环境变量去告诉它这个指令在哪里不用我们写路径【二】常见的环境变量名各个环境变量名有自己的功能可以利用echo $环境变量名进行查询各种信息环境变量名作用记录的内容是哈查看方法终端敲命令PATH告诉系统 “去哪里找命令”最核心echo $PATHHOME你的 “家目录” 路径cd ~就是去这里echo $HOMEUSER当前登录的用户名谁在用这个终端echo $USERSHELL当前Shell,它的值通常是/bin/bashecho $SHELLLD_LIBRARY_PATH程序运行时找动态库的路径列表echo $LD_LIBRARY_PATH.bashrc/.zshrc每次打开终端都会自动执行的配置文件echo $SHELL例如【三】环境变量添加添加到系统的环境变量环境变量名$环境变量名 : 添加路径1临时如果我们后面需要自己添加环境变量那么根据分类添加时需要注意是全局还是局部直接定义变量比如age20默认是局部变量只有当前终端能用打开新终端就没了用export声明比如export age20变成全局变量新打开的子终端也能看到例如我们每次在执行编译好的可执行程序时需要加前缀./现在可以添加路径直接调用例如我现在要添加一个全局变量需要使用export声明2永久先执行echo $SHELL如果输出是/bin/bash用.bashrc配置如果输出是/bin/zsh用.zshrc配置假设是输出是bashnano ~/.bashrc然后在末尾正常添加环境变量即可【四】环境变量查看1可以使用 echo 查看已经存在的单个环境变量例如2使用 env指令 查看所有环境变量例如3使用 set 指令查看所有变量含局部变量和函数4通过库函数 getenv获取环境变量内容#include stdlib.h char *getenv(const char *name);例如打印单个的环境变量【五】命令行参数命令行参数命令行参数可以理解成“给程序的‘额外指令’”让程序知道 “要做什么、用什么数据、以什么方式做”。这里我们以main函数的命令行参数为例1argc与argvargc统计命令行参数的 “总数”argv存储命令行参数的 “字符串数组”末尾是nullptr可以看到包括我们输入的./Hello也是一个字符串命令行参数从0开始根据空格划分个数2envenv或envp存储环境变量的 “字符串数组”末尾是nullptr因此我们可以利用env来打印环境变量【六】进程的启动进程启动时会被传两张表命令行参数表和环境变量表。给这个进程提供各种路径和更多选项每个进程都有专属的 “当前工作目录”。当我们用 fork 函数创建自己的子进程之后子进程可以在子进程的代码分支中调用chdir函数修改工作目录而子进程的修改不影响父进程二者是独立的【七】进程地址空间什么是进程地址空间进程的产生到结束中间的过程是如何的为方便理解由现象-出概念1前引首先我们用 fork 函数来产出一个子进程然后更改父\子进程的数据看看是什么现象可以看到虽然 n 的修改可以看出各个进程是独立的数据但是注意 n 的地址每次都是相同的可以确认这里的 n地址 绝对不是物理地址引入新概念这里n地址属于虚拟地址或线性地址2原理讲解当一个进程被创建的时候之前对它的解释是进程PCB数据结构对象代码数据即但是今天要更加完善一些需要引入且完善对进程的了解在进程的PCB被操作系统创建出来同时1会产生一个进程地址空间由PCB内的指针指向它进程地址空间进程地址空间理解为一个真正物理内存的投影来映射该进程物理内存分布既然是映射那么物理内存的分布也回直接映射在虚拟内存作用隔离进程之间互不干扰一个进程崩溃不会影响系统和其他进程防止该进程出现问题影响真正的物理内存进而影响其它进程简化编程程序员不用关心真实物理内存布局只用关心虚拟地址不用管物理内存如何分布只需要知道“有”这个地方就行2进程地址空间和真正的物理内存共同存在一个页表Linux 使用页表来管理映射里面 左边和右边各自放自己的地址Linux会通过页表存储的地址来拿到物理/进程地址空间我们画出整个关系图如下3创建子进程创建子进程时子进程会拷贝父进程的进程地址空间和物理内存如果子进程需要更改数据再在物理内存上单独开一块空间达到互相独立的数据写时拷贝4页表我们先看下面几个概念结合图片理解1进程先访问的是虚拟地址进程自己的真实物理映射地址但数据实际存在物理内存真实 的硬件内存空间里面2CPU 要 “翻译” 虚拟地址时得先找到页表在哪里。cr3寄存器就是 CPU 里的一个特殊 “指 针”它存储着当前进程页表的起始地址3页表用来放进程地址空间和物理内存各个范围分布的地址同时标注这块区域的权限和资 源状态比如0和14进程要访问某个虚拟地址比如执行一段代码、读取一个变量时进程的代码数据不会全部加载到内存而是按需加载每次加载一部分内存空间有限CPU通过查询 cr3 指针找到页表中对应的这块资源状态如果为0表示缺乏会告诉操作 系统需要去磁盘取这块资源随后操作系统更新页表【八】究极逻辑详解产生PCB当一个进程被创建时首先形成的是PCBtask_struct结构对象产生进程地址空间和物理内存同时在PCB里面有一个指针指向了这个进程的进程地址空间即虚拟内存本质类似PCB也是一个结构对象这个虚拟内存是这个进程在真实物理内存的映射包含了物理内存的严格区域、范围划分等信息产生页表操作系统从进程地址空间中提取该进程的物理地址同时为该进程生成页表用来放置对应各个区域的虚、物理地址和权限、状态信息cr3管理cr3是CPU的控制寄存器来指向当前进程的页表通过cr3CPU才可以访问到页表当更新进程时只需要完成PCB的描述更换cr3指向更新页表即可思维图如下进程的运行当进程需要调/修改某个资源时CPU会通过 cr3 指针访问页表查看该资源空间对应 的状态如果缺乏会让操作系统去磁盘加载或者权限不允许则会结束该次请求进程 内核PCB 代码数据 进程地址空间 页表