一、先认识环境变量它到底是什么先建立一个流程接下来细节理解我们平时使用 Linux 的时候经常会输入各种命令比如lspwdgcc这些命令都可以直接运行。但是当我们自己写了一个 C 语言程序编译之后却经常需要这样运行./test为什么系统自带的命令可以直接运行而我们自己写的程序却需要加上./呢其实这就涉及 Linux 中一个很重要的概念环境变量。环境变量说白了就是程序运行时需要的一些环境信息。比如当前用户是谁、家目录在哪里、系统应该去哪些目录寻找可执行程序等。这些信息会影响程序的运行所以操作系统需要有一种方式把这些信息提供给程序使用。我们可以先把环境变量理解成程序运行时随身携带的一份环境信息。这里还要区分一个概念普通变量和环境变量。比如我们在 Shell 中定义一个普通变量nameYi这时候当前 Shell 可以使用这个变量echo$name但是普通变量并不会自动传递给之后创建的子进程。如果我们使用exportname就相当于把这个变量导出为环境变量之后创建的子进程也可以获得它。所以两者最主要的区别是普通变量主要在当前 Shell 中使用。环境变量除了当前 Shell 使用还可以传递给之后创建的子进程。理解这一点后面学习环境变量的继承就容易多了。二、环境变量都有哪些先认识几个常见的Linux 中有很多环境变量不同的环境变量保存着不同的信息。我们先认识几个比较常见的。1. PATH系统去哪里找命令这是我们最需要理解的一个环境变量。比如我们平时输入ls系统为什么能够找到ls呢因为 PATH 中保存了一些目录Shell 会根据这些目录去寻找对应的可执行程序。我们可以通过下面的命令查看echo$PATH可能会看到类似这样的结果/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin这里有很多目录它们之间使用冒号:分隔。也就是说PATH 保存的不是某一个程序而是一系列目录。当我们输入命令时Shell 就可以根据 PATH 中的目录去寻找对应的程序。2. HOME当前用户的家目录echo$HOME它保存的是当前用户的家目录。比如/home/ubuntu当我们输入cd~就可以回到当前用户的家目录。3. USER当前用户名echo$USER它保存当前用户的用户名。例如ubuntu4. PWD当前所在目录echo$PWD它保存当前 Shell 的工作目录。比如/home/ubuntu这些环境变量保存的信息不同但是作用都是为程序提供运行环境所需要的信息。三、环境变量怎么使用先从 Linux 命令开始认识了环境变量之后我们再来看看怎么查看、设置和删除它们。1. echo查看指定环境变量如果我们只想查看某一个环境变量可以使用echo$PATH这里的$表示取出变量对应的值。比如echo$HOME就可以查看当前用户的家目录。2. env查看环境变量列表如果我们想一次性查看当前 Shell 中导出的环境变量可以使用env它会把当前环境中的环境变量打印出来。例如USERubuntu HOME/home/ubuntu PATH/usr/local/sbin:/usr/local/bin:/usr/bin PWD/home/ubuntu这样就能看到当前环境中有哪些变量。3. export设置并导出环境变量比如我们想创建一个自己的环境变量exportMY_NAMEYi然后查看echo$MY_NAME就能得到Yi这里要注意export不仅可以设置变量还可以把原本的普通 Shell 变量导出为环境变量。例如MY_NAMEYiexportMY_NAME这两条命令和直接使用export MY_NAMEYi的效果类似。4. unset删除环境变量如果我们不再需要某个变量可以使用unsetMY_NAME再查看echo$MY_NAME就不会再得到原来的值了。到这里我们已经掌握了环境变量最基本的操作命令作用echo $变量名查看指定变量env查看环境变量列表export设置或导出环境变量unset删除变量四、重点理解 PATH为什么有些命令不用 ./ 就能运行前面认识了 PATH现在我们单独拿它出来理解一下。我们先看一个实际场景。假设我们写了一个简单的 C 程序#includestdio.hintmain(){printf(hello Linux!\n);return0;}编译gcc test.c-otest运行./test这里为什么要加./呢因为我们输入命令时Shell 需要知道去哪里寻找对应的可执行程序。比如我们直接输入lsShell 会根据 PATH 中的目录去寻找ls。但是我们自己编译出来的test一般放在当前目录而当前目录通常不在 PATH 中。所以直接输入testShell 就可能找不到这个程序。而./test这里的.表示当前目录./test就是在明确告诉 Shell去当前目录寻找 test 程序。这就是两种运行方式的区别。动手实验把自己的程序加入 PATH既然 PATH 决定了 Shell 去哪里寻找程序那么我们能不能把自己的程序所在目录也加入 PATH 呢当然可以。比如当前程序放在/home/ubuntu/test我们可以执行exportPATH$PATH:/home/ubuntu这里$PATH保留原来的搜索目录。:分隔不同目录。/home/ubuntu新增一个搜索目录。这样Shell 就可以在/home/ubuntu中寻找可执行程序了。如果程序名是test就可以直接输入test不需要再写./test。这也说明了 PATH 的作用它只是告诉 Shell 去哪些目录寻找命令并不是把程序本身放进 PATH。五、程序也能获取环境变量吗前面我们都是在 Linux 命令行中操作环境变量。那么问题来了如果我们自己写了一个 C 语言程序能不能在程序内部获取环境变量呢当然可以。C 语言提供了几个常用函数。1. getenv()获取环境变量这个函数的作用就是根据环境变量的名字获取对应的值。例如#includestdio.h#includestdlib.hintmain(){char*pathgetenv(PATH);if(path!NULL){printf(%s\n,path);}return0;}这里getenv(PATH);就是获取 PATH 环境变量的值。如果找到了就返回对应字符串的地址如果没有找到就返回NULL。所以我们在使用时最好先判断一下返回值是否为空。2. setenv()设置环境变量如果我们想在 C 程序中设置一个环境变量可以使用setenv(MY_NAME,Yi,1);这里三个参数分别表示MY_NAME环境变量的名字。Yi环境变量的值。1如果变量已经存在允许覆盖原来的值。如果最后一个参数是0则表示变量已经存在时不覆盖。3. unsetenv()删除环境变量如果想删除一个环境变量可以使用unsetenv(MY_NAME);这样就可以删除当前进程环境中的这个变量。这里需要注意这些函数修改的是当前进程自己的环境不会直接修改父进程的环境变量。通过这几个函数我们就可以在 C 语言程序中获取、设置和删除环境变量了。六、环境变量在程序中是怎么存放的前面我们已经知道程序可以通过getenv()获取环境变量。但是这里又有一个问题环境变量那么多程序到底是怎么把它们组织起来的呢其实它们是通过一张环境变量表来组织的。比如我们可以把环境变量想象成下面这样环境变量表 | |---- PATH/usr/bin:/bin | |---- HOME/home/ubuntu | |---- USERubuntu | |---- PWD/home/ubuntu | |---- NULL可以看到环境变量表中保存着一个个字符串的地址每个字符串都包含变量名和对应的值。而且最后还有一个NULL表示环境变量表已经结束。那么在 C 语言中我们怎么访问这张表呢这里就要认识一个东西environ。environ 是什么在 Linux 中我们可以通过下面的方式声明externchar**environ;environ是一个全局变量它指向当前进程的环境变量表。这里为什么使用char**呢我们拆开来看char*可以指向一个字符串。char**可以指向一个存放字符串指针的数组。而环境变量表刚好就是由多个字符串指针组成的所以使用char**来表示。我们可以通过下面的代码遍历环境变量表#includestdio.hexternchar**environ;intmain(){inti0;while(environ[i]!NULL){printf(%s\n,environ[i]);i;}return0;}这里的逻辑很简单environ指向环境变量表。environ[i]取出其中一个环境变量字符串。使用printf打印。遇到NULL就停止遍历。这样就能把当前进程的环境变量全部打印出来。七、main 函数的第三个参数envp前面我们学习命令行参数时接触过argc和argv。比如intmain(intargc,char*argv[])其中argc命令行参数的个数。argv命令行参数表。例如我们执行./test hello world那么参数大致是argc 3 argv[0] ./test argv[1] hello argv[2] world argv[3] NULL注意最后的NULL不计算在argc中。那么 main 函数其实还可以有第三个参数intmain(intargc,char*argv[],char*envp[])这个envp就是环境变量表。也就是说程序启动时除了可以接收到命令行参数还可以接收到环境变量。我们可以通过下面的代码验证#includestdio.hintmain(intargc,char*argv[],char*envp[]){inti0;while(envp[i]!NULL){printf(%s\n,envp[i]);i;}return0;}运行之后就可以看到程序接收到的环境变量。这里我们可以把三个参数放在一起理解参数作用argc命令行参数的个数argv命令行参数表envp环境变量表其中argv和envp都是字符串指针数组并且都以NULL作为结束标志。它们保存的内容不同但组织形式很相似。这里补充一点第三个参数envp是 Linux 等系统中常见的用法并不是 ISO C 标准规定的 main 函数参数形式。八、环境变量为什么能被子进程继承前面我们知道了环境变量表也知道了程序可以通过envp获取环境变量。但是还有一个问题我们在 Shell 中设置的环境变量为什么自己运行的 C 程序也能获取到这就涉及父进程和子进程了。假设现在有一个 Shell 进程我们执行exportMY_NAMEYi这时MY_NAME就成为了 Shell 的环境变量。接下来我们执行./testShell 会创建子进程来执行这个程序。那么子进程能不能获得父进程中的MY_NAME呢答案是可以的。因为子进程在创建时会继承父进程的环境。所以在test程序中我们可以直接使用getenv(MY_NAME);获取到Yi子进程修改环境变量会影响父进程吗这里还有一个容易混淆的地方。既然子进程可以继承父进程的环境变量那么子进程修改环境变量是不是也会改变父进程的环境变量呢答案是不可以。因为子进程获得的是自己的一份环境数据。例如父进程中exportMY_NAMEYi子进程中通过setenv()把MY_NAME改成其他值。这个修改只影响子进程自己的环境不会反过来改变父进程中的变量。所以我们可以记住父进程可以把环境变量传递给子进程但是子进程对自己环境变量的修改不会直接影响父进程。这也是环境变量继承的一个重要特点。九、把整个知识点串起来到这里我们已经学习了环境变量的定义、常见命令、C 语言接口以及环境变量在进程之间的继承。最后我们把这些知识联系起来。1. 环境变量从哪里来环境变量可以由系统、Shell 或程序设置。比如我们在 Shell 中执行exportMY_NAMEYi就为当前 Shell 设置了一个环境变量。2. 环境变量怎么被程序使用程序启动时可以获得环境变量表。我们可以通过getenv()根据名字获取某个环境变量。environ访问当前进程的环境变量表。envp通过 main 函数的第三个参数获取环境变量表。3. 环境变量怎么传递当 Shell 创建子进程运行程序时子进程会继承父进程的环境变量。所以我们在 Shell 中设置的环境变量程序也能够使用。4. 最后记住这条知识线Shell 设置环境变量 | v export | v Shell 环境变量表 | v 创建子进程并执行程序 | v 子进程继承环境变量 | v 程序通过 getenv / environ / envp 获取总结一下环境变量本质上就是一组保存程序运行环境信息的变量。Shell 可以设置和管理它们程序可以通过 C 语言提供的接口获取它们而子进程又可以继承父进程的环境变量。从最开始的PATH到后面的getenv()、environ和envp其实讲的都是同一件事环境变量如何产生、如何保存以及如何被程序使用。
企业数字化 ERP 产品动态
相关推荐
Agent 开发核心知识点:从 Chatbot 到会干活的模型 前言Chatbot 只会聊天,Agent 会调用工具、拆解任务、自己纠错。这一波 AI 应用落地的核心就是 Agent。这篇不讲虚的,讲清楚
Agent 的循环结构、Function Calling 的机制和工程上必须处理的问题。一、Agent 的组成
一个 Agent 通常包含四部分:… · 2026/11/4 12:05:57
大模型小白入门:揭秘ChatGPT如何预测下一个字,收藏这篇轻松上手! 本文用7张示意图,深入浅出地解析了大语言模型(LLM)的技术链条。核心在于,LLM通过不断预测下一个字元来运作,从将语言数字化、预训练到生成回答,再到指令微调和人类反馈强化学习,最终形成强大的语… · 2026/11/4 12:04:56
现代爬虫技术:Selenium处理JavaScript渲染与反爬策略 1. 为什么现代爬虫必须处理JavaScript渲染? 十年前我刚入行做爬虫的时候,90%的网站直接requestsBeautifulSoup就能搞定。但现在打开Chrome开发者工具随便看个电商网站,满屏的XHR请求和动态加载的JSON数据都在提醒我们:传统爬虫技术… · 2026/11/4 12:45:30
Cybersecurity期刊投稿全流程:定位、审稿与返修策略 1. 先搞清楚这本刊在学术版图里到底站在哪个位置1.1 从刊名开始的第一层误读Cybersecurity 这个词写在刊名上,绝大多数人第一反应是"安全领域的综合大刊",然后拿它去对标那些办了二三十年、影响因子长期稳定在高位的老牌安全刊物。我第一次接触… · 2026/11/4 12:45:30
跨模态检索技术与以图搜图系统架构详解 1. 跨模态检索技术全景解析 当你在电商平台用手机拍下街边橱窗里的同款包包,或是用一段文字描述在视频库里精准定位某个片段时,背后发挥作用的正是跨模态检索技术。这项技术正在重塑我们与数字世界的交互方式,其核心在于建立不同模态数据&… · 2026/11/4 12:45:30
大模型解数学题的底层原理:从语言建模到思维链涌现 1. 一个反直觉的起点:数学题不是“算出来”的,而是“生成出来的” 很多人第一次看到大模型解出微分方程或组合数列题时,下意识会想:“它是不是内置了Mathematica内核?”“是不是偷偷调用了SymPy?”——这种… · 2026/11/4 12:45:30
CPXS三表十四题:SQL嵌套查询、NOT EXISTS与避坑实践 简介:《数据库实验5嵌套查询》是一份面向数据库课程学习者与实验教学场景的文档型实验报告,围绕CPXS数据库展开统计查询、连接查询与嵌套查询的训练,适合正在学习SQL查询、准备课程实验或需要巩固查询语法的高校学生与自学者参考。资源包共1个… · 2026/11/4 12:45:30
WEKA数据挖掘入门:ARFF格式、预处理与J48分类基线 简介:面向初学数据挖掘、准备上手 WEKA 的读者,这份文档围绕“weak 操作入门”梳理平台的基本概念与操作路径,适合作为课程实验、自学入门或数据分析的前置阅读。压缩包仅含 1 个 doc 文件,约 172KB,篇幅集中ÿ… · 2026/11/4 12:44:30
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38