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

Linux系统之美:环境变量的概念以及基本操作

本节重点

  • 理解环境变量的基本概念
  • 学会在指令和代码操作上查询更改环境变量
  • 环境变量表的基本概念
  • 父子进程间环境变量的继承与隔离

一、引入

1.1 自定义命令(我们的exe)

 我们以往的Linux编程经验告诉我们,我们在对一段代码编译形成可执行文件后执行可执行文件必须声明可执行文件所在的路径,路径可以是相对路径也可以是绝对路径:

而如果我们不加上 ./ 也就是不加上可执行文件的完整路径,系统就会出现以下报错:

表示命令行解释器(bash)无法找到该命令的可执行文件和该命令的实现方法。

1.2系统命令的实现:

系统命令的实现与上述别无二致,其主要步骤如下:

a、开发者使用编程语言(如C、C++、Shell等)编写命令的源代码。源代码包含了实现命令功能的逻辑和算法。

b、使用编译器(如gcc)将源代码编译成目标文件(.o文件),然后将目标文件链接成可执行文件。在链接过程中,编译器会链接所需的库文件,确保命令能够正常运行。

c、将编译生成的可执行文件安装到系统的某个目录中,通常是/usr/bin/sbin/usr/sbin、/等标准目录中。

所以系统命令本质上也是可执行文件,当我们在命令行输入系统命令如 ls 、cd、touch、mkdir时,bash(命令行解释器)会将命令进行解析检查命令是否合法,当合法时bash就会创建子进程来执行该命令。

对于系统命令来说,bash(命令行解释器)会自动在/usr/bin/sbin/usr/sbin、/bin等标准目录中查找相应命令的可执行文件(也就是实现方法),找到之后执行可执行文件即可。

而对于我们“自定义的命令”也就是我们的可执行文件来讲,当我们输入可执行文件的文件名时bash也会自动在/usr/bin/sbin/usr/sbin、/bin等标准目录中查找对应的可执行文件,结果当然是找不到所以就会报错(Command not found)。

1.3 引入环境变量

当我们登录Linux系统时bash进程就会被创建,同时bash进程会从系统文件中配置并维护一批环境变量来指定运行环境参数,其中 PATH 就是其中之一,其指定了/usr/bin、/sbin、/usr/sbin、/bin等标准目录:

当用户在命令行或脚本中输入一个命令或程序名时,操作系统会根据PATH环境变量的值去查找该命令或程序的可执行文件,如果找到了相应的可执行文件,操作系统就会执行它;如果没有找到,操作系统会报错,提示“命令无法识别”或类似的错误信息。

二、基本概念

在Linux系统中,环境变量是一种用于存储影响进程行为和运行的动态值的机制。环境变量是由操作系统或用户设置的,可以被系统和应用程序在运行时访问和使用。它们通常用于定义系统配置、路径设置、用户偏好等。

格式:

环境变量名 = 内容

如环境变量PATH:

一个环境变量可能会有多个内容(值),不同内容(值)之间用 :隔开。 

在命令行界面我们可以使用 env 来查看所有环境变量以及内容:

如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

三、获取环境变量

3.1 指令操作

1> env

功能:查看所有或特定的环境变量

#查看所有的环境变量
env
#查看特定的环境变量(如PATH)
env | grep PATH

示例:查看特定的环境变量HOME

 

2> export

功能:设置或者更改环境变量

设置一个环境变量

export 变量名=内容

示例:设置一个新环境变量value

export value=/home/yjh/linux-learning

 

 更改一个环境变量的内容(临时):

全部更改:

export 变量名=新内容

追加更改:

export $变量名=:新内容

 示例:在环境变量PATH之后再追加一段路径/home/yjh/linux-learning

export $PATH:/home/yjh/linux-learning

3> echo

功能:查看环境变量的内容

echo $变量名

 示例:查看环境变量PATH的内容

4> unset

功能:删除某一个环境变量

unset 变量名

 示例:

3.2 代码操作

除了在命令行窗口用指令获取环境变量的内容,在代码之中我们也可以通过getenv等库函数获得对应环境变量的内容,以便于我们配置和管理运行时行为。

1> 通过父进程(bash等)获取

在理解这个概念之前我们需要明白的是main函数是什么,main函数的参数究竟有几个,main函数被谁调用这几个问题,下面我们对这些问题一一进行解答:

首先main函数是我们C程序的唯一入口点,操作系统会加载可执行文件,并寻找main函数作为执行的起点。在C语言中main函数有以下两种标准形式:

  • int main( void )
  • int main( int argc , char * argv[] )

第一种是我们常见的无参形式即不需要传递参数,第二种接受命令行参数,其中argv是一个字符串数组,而argc表示该数组中的元素个数,关于命令行参数的相关知识我们后续实现自定义shell(命令行解释器)时会给大家一一讲解。

其实在C标准中,main函数还支持第三个参数即环境变量表,所以C标准允许main函数所定义的形式为:

int main(int argc,char* argv[],char* env[])
{return 0;
}

其中env是一个指向环境变量字符串数组的指针,每个字符串格式为 NAME=value 。不过,这个参数在C标准中是可选的,不是所有实现都支持。例如,在Windows的某些编译器中,可能不支持env 参数,或者需要通过其他方式获取环境变量。

这里我们来写一个简单的代码打印验证一下我们通过main函数获取的环境变量:

#include<stdio.h>
int main(int argc,char* argv[],char* env[])
{(void)argc;(void)argv;for(int i=0;env[i];i++){//打印数组中的每一个元素printf("%s\n",env[i]);                                                                                                                  }printf("\n");return 0;
}

运行结果:

 其中这个env字符串数组还有一个名字就是环境变量表。前面我们说过当我们登录Linux系统时系统就会给我们自动创建一个bash进程,之后我们进行的一系列命令,写的一系列代码运行起来都是bash的子进程,当我们的C程序进程被创建时bash就会调用一系列系统调用将环境变量传递给子进程形成一张环境变量表,子进程通过char* env[ ] 参数或全局变量 extern char** environ访问这些环境变量。

举个例子,当我们在bash中对环境变量进行一系列增删查改时,结果也可以在子进程(我们的C程序)中看到:

设置一组新环境变量:

export value1=123456
export value2=yjh
export value3=jzq
export value4=hello

此时再打印我们C程序中的环境变量表内容发现也可以看到新增环境变量:

2>  getenv

getenv 是一个在C标准库(<stdlib.h>)中定义的用于获取环境变量值的函数

函数原型:

char *getenv(const char *name);

功能:接受一个字符串name表示要查询的环境变量的名称,成功返回 char* 类型指向该环境变量的指针(字符串),失败返回NULL(变量不存在或不可访问)。

底层原理:全局变量environ(extern char** environ)

上面我们说过,当我们的C程序的进程被创建时,bash就会通过调用系统调用将环境变量传递给子进程(我们的C程序),形成一张环境变量表而子进程可以通过参数env或者environ来接受,其中environ是一个指向环境变量表(字符串数组)的指针。

而getenv函数内部通过遍历environ查找匹配的变量名,并返回对应环境变量的内容。

示例:查询环境变量PATH的内容

#include<stdio.h>
#include<stdlib.h>int main()
{char* value=getenv("PATH");if(value==NULL){printf("getenv fail\n");}else{printf("PATH->%s\n",value);}return 0;
}

运行结果:

3> environ指针

在Linux系统中,environ是一个全局变量,指向环境变量字符串数组的指针。它允许程序直接访问系统环境变量(如PATH、HOME等)。

类型extern char** environ(C语言中声明为全局变量)

内容:每个字符串格式为 name=value 例如:PATH=/usr/local/sbin

用途:程序可通过 environ 直接读取或修改环境变量

示例:

使用environ打印所有的环境变量:

#include<stdio.h>                                                                                                                                        
#include<stdlib.h>
#include<unistd.h>
extern char** environ;
int main()
{for(char **env=environ;*env!=NULL;env++){printf("%s\n",*env);}return 0;
}

运行结果:

四、环境变量表

4.1 基本概念

在Linux系统中环境变量表实际上指的是存储环境变量的数据结构其本质上是一个字符串数组,它在程序启动时从父进程中被继承并在程序运行过程中可以被访问和修改。

4.2 环境变量表的产生

4.2.1 子进程中拷贝自父进程

在子进程中的环境变量表由父进程传递而来,也就是说当子进程被创建时父进程会拷贝一份自己的环境变量表传递给子进程,这里我们可以做一个小示例:

当我们在父进程(这里是bash)中对环境变量表进行一系列增删查改后,此时我们运行自己的C程序(创建bash的子进程)会发现子进程中的环境变量表也发生了改变。

在bash(父进程)设置一组新环境变量:

export value1=123456
export value2=yjh
export value3=jzq
export value4=hello

 此时打印我们C程序(子进程)中的环境变量表内容发现也可以看到新增环境变量:

注意:子进程中修改环境变量表不会影响父进程

也就是说父子进程中的环境变量表都是独立的副本,子进程被创建时父进程会拷贝自己的环境变量表加载到子进程,而子进程对自己环境变量表的修改不会影响到父进程,只会影响当前的子进程及其后续创建的子进程

4.2.2 父进程(bash)中来自系统配置

在前面我们了解到,子进程中的环境变量表由父进程中拷贝而来,而父进程(bash)中的环境变量表从何而来呢?答案是从系统配置文件而来。

在前面我们学习了一系列指令用于在命令行窗口中设置或更改环境变量,例如export和unset指令,但实际上这些操作都具有临时性,当我们退出系统并重新登录时,就会发现我们修改的结果并没有永久生效,系统会重新生成一份全新的默认的环境变量表:

在bash中新增一组环境变量:

export value1=123456
export value2=yjh
export value3=jzq
export value4=hello

此时我们可以看到新增后的结果:

当我们退出系统重新登录Linux后执行env会发现新增的一组环境变量不见了:

 bash中的环境变量来源于系统级或者用户级配置文件~/.bashrc~/.bash_profile等,export或unset指令并没有对系统配置文件进行修改所以其更改具有临时性,当我们再次登录时系统就会根据配置文件生成全新的默认的环境变量表。

五、总结

在这次学习中我们首先通过自定义可执行文件与系统指令运行时的差异上引出了环境变量的概念,之后我们了解了PATH环境变量的作用:命令行解释器(shell)通过PATH的内容遍历标准目录来查找相关指令的可执行文件,找到就运行文件找不到就报Command not found 等类似错误。

之后我们分别在指令操作与代码操作两个方面总结了查询或更改环境变量的指令与函数,在这里我们提到了环境变量的”继承性“与差异,即当子进程创建时父进程就会拷贝一份自己的环境变量表加载到子进程,而子进程对自己环境变量表的更改不会影响到父进程。

最后我们谈到了环境变量表的由来:即子进程中由父进程拷贝并加载而来,父进程(bash)中则来源于系统的配置文件。

相关文章:

Linux系统之美:环境变量的概念以及基本操作

本节重点 理解环境变量的基本概念学会在指令和代码操作上查询更改环境变量环境变量表的基本概念父子进程间环境变量的继承与隔离 一、引入 1.1 自定义命令&#xff08;我们的exe&#xff09; 我们以往的Linux编程经验告诉我们&#xff0c;我们在对一段代码编译形成可执行文件后…...

数学爱好者写的编程系列文章

作为一个数学爱好者&#xff0c;我大学读的专业却不是数学专业&#xff0c;而是跟计算机有关的专业。原本我对编程一窍不通&#xff0c;平时上课也是在看数学文献&#xff0c;作业基本靠同学&#xff0c;考试及格就行。不过后来因为毕业的压力&#xff0c;我还是拥抱编程了&…...

pnpm 报错 Error: Cannot find matching keyid 解决

1. 查看corepack版本&#xff0c;升级至0.31.0 npm i -g corepack0.31.0 这里注意环境变量&#xff0c;可能升级后还是指向旧版本&#xff0c;可以选择更新环境变量或者删除原指向的corepack命令 2. 更新pnpm corepack install -g pnpmlatest 问题解决。...

dcat-admin已完成项目部署注意事项

必须 composer update 更新项目php artisan admin:publish 发布dcatadmin的静态资源手动创建目录&#xff08;如果没有&#xff09; storage/appstorage/framework/cachestorage/framework/sessionsstorage/framework/views 需检查 php不要禁用以下函数 putenvsymlinkproc_…...

Ubuntu实时读取音乐软件的音频流

文章目录 一. 前言二. 开发环境三. 具体操作四. 实际效果 一. 前言 起因是这样的&#xff0c;我需要在Ubuntu中&#xff0c;实时读取正在播放音乐的音频流&#xff0c;然后对音频进行相关的处理。本来打算使用的PipewireHelvum的方式实现&#xff0c;好处是可以直接利用Helvum…...

大语言模型进化论:从文本理解到多模态认知的革命之路

一、Transformer&#xff1a;认知革命的基石 ### 1.1 自注意力机制&#xff1a;神经网络的"量子纠缠" python # 自注意力核心公式实现 def self_attention(Q, K, V, maskNone): d_k Q.size(-1) scores torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(…...

《Operating System Concepts》阅读笔记:p460-p4470

《Operating System Concepts》学习第 36 天&#xff0c;p460-p4470 总结&#xff0c;总计 11 页。 一、技术总结 无。 二、英语总结(生词&#xff1a;3) 1.lifespan (1)lifespan: life span(“the period of time that sth exists or happens”) c. 也写作 life-span, …...

Postgresql 删除数据库报错

1、删除数据库时&#xff0c;报错存在其他会话连接 ## 错误现象&#xff0c;存在其他的会话连接正在使用数据库 ERROR: database "cs" is being accessed by other users DETAIL: There is 1 other session using the database.2、解决方法 ## 终止被删除数据库下…...

Fiddler抓包工具最快入门

目录 前言 了解HTTP网络知识 简单了解网络访问过程 简单了解HTTP网络传输协议 工作过程 HTTP请求&#xff1a; Fildder工具使用教程 抓包的概念 一、什么是抓包 二、为什么要抓包 三、抓包的原理&#xff08;图解&#xff09; Fiddler工具 安装 使用 Fiddler查看…...

编译器与中间表示:LLVM与GCC、G++、Clang的关系详解

编译器与中间表示&#xff1a;LLVM与GCC、G、Clang的关系详解 引言 编译器是软件开发中不可或缺的工具&#xff0c;它负责将高级语言&#xff08;如C/C、Java等&#xff09;转换为机器语言&#xff0c;使计算机能够理解和执行程序。中间表示&#xff08;Intermediate Represe…...

《深度剖析:鸿蒙系统不同终端设备的UI自适应布局策略》

在万物互联的时代&#xff0c;鸿蒙系统以其独特的分布式理念和强大的技术架构&#xff0c;迅速在智能终端领域崭露头角。随着鸿蒙生态的不断壮大&#xff0c;越来越多的开发者投身其中&#xff0c;致力于为用户打造丰富多样的应用体验。然而&#xff0c;如何让应用在不同终端设…...

股指期货贴水波动,影响哪些投资策略?

先来说说“贴水”。简单来说&#xff0c;贴水就是股指期货的价格比现货价格低。比如&#xff0c;沪深300指数现在是4000点&#xff0c;但股指期货合约的价格只有3950点&#xff0c;这就叫贴水。贴水的大小会影响很多投资策略的收益&#xff0c;接下来我们就来看看具体的影响。 …...

1.1 结构体与类对象在List中使用区别

一、问题的起源如下的代码是错误的&#xff0c;无法编译通过 struct Point {public int X;public int Y; }List<Point> points new List<Point> { new Point { X 1, Y 2 } }; points[0].X 10; // 编译错误&#xff01;无法修改副本的字段 二、原因分析 在C#中&…...

matlab近似计算联合密度分布

在 Matlab 中&#xff0c;当A和B是两个序列数据时&#xff0c;可以通过以下步骤来近似求出A大于B的概率分布&#xff1a;数据准备&#xff1a;确保序列A和B具有相同的长度。如果长度不同&#xff0c;需要进行相应的处理&#xff08;例如截取或插值&#xff09;。计算A大于B的逻…...

基于WebAssembly的浏览器密码套件

目录 一、前言二、WebAssembly与浏览器密码套件2.1 WebAssembly技术概述2.2 浏览器密码套件的需求三、系统设计思路与架构3.1 核心模块3.2 系统整体架构图四、核心数学公式与算法证明4.1 AES-GCM加解密公式4.2 SHA-256哈希函数五、异步任务调度与GPU加速设计5.1 异步任务调度5.…...

RHCE 使用nginx搭建网站

一。准备工作 Windows dns映射 创建目录网页 vim 编辑内容 添加如下 重启nginx服务&#xff0c;在Windows浏览器进行测试...

pcap流量包分析

先说一个阿里云学生无门槛免费领一年2核4g服务器的方法&#xff1a; 阿里云服务器学生无门槛免费领一年2核4g_阿里云学生认证免费服务器-CSDN博客 PCAP文件是一种网络数据包捕获文件格式&#xff0c;通常被用来捕获和存储网络流量数据。对PCAP文件进行分析可以帮助识别网络中的…...

OpenCV专利收费免费模块介绍

一、核心模块&#xff08;免费&#xff0c;商业 / 非商业均可使用&#xff09; ML 模块&#xff08;机器学习&#xff09; 功能&#xff1a;支持向量机&#xff08;SVM&#xff09;、K 均值聚类、神经网络&#xff08;ANN&#xff09;等。收费状态&#xff1a;免费。属于 OpenC…...

AtCoder Beginner Contest 398(ABCDEF)

A - Doors in the Center 翻译&#xff1a; 找到一个满足下面情况长为N的字符串&#xff1a; 每个字符是 - 或 。是一个回文。包含一个或两个 。如果包含两个相邻的 。 如此字符串为独一无二的。 思路&#xff1a; 从两端使用 开始构造回文。在特判下中间部分&#xff0c;…...

单表达式倒计时工具:datetime的极度优雅(智普清言)

一个简单表达式&#xff0c;也可以优雅自成工具。 笔记模板由python脚本于2025-03-22 20:25:49创建&#xff0c;本篇笔记适合任意喜欢学习的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思考与经验&#xff0c;而不仅仅是知识的简单复述。 Pyth…...

【2025 深圳大学-腾讯云程序设计竞赛(热身赛)】题解

比赛链接 A. Cloud Studio的共享连接 题目大意 && Solution 给定 T T T 组长度均为 12 12 12 的字符串 s s s。 对每个 s s s&#xff0c;将其按从左到右的顺序两两分组形成 6 6 6 个 A S C I I \rm{ASCII} ASCII 码&#xff0c;对这 6 6 6 个 A S C I I \…...

C语言基础与进阶学习指南(附运行效果图及术语解析)

C语言基础与进阶学习指南&#xff08;附运行效果图及术语解析&#xff09; 目录 C语言标准与编译流程CPU与内存基础C语言基础语法数据类型详解变量与内存管理运算符与表达式输入输出函数函数与内存管理指针与内存操作结构体与高级应用 1. C语言标准与编译流程 1.1 C语言标准演…...

2025年3月GESP八级真题解析

第一题——上学 题目描述 C 城可以视为由 n n n 个结点与 m m m 条边组成的无向图。这些结点依次以 1 , 2 , … , n 1,2,…,n 1,2,…,n 标号&#xff0c;边依次以 1 , 2 , … , m 1,2,…,m 1,2,…,m 标号。第 i i i 条边&#xff08; 1 ≤ i ≤ m 1≤i≤m 1≤i≤m&#…...

C++继承机制:从基础到避坑详细解说

目录 1.继承的概念及定义 1.1继承的概念 1.2 继承定义 1.2.1定义格式 1.2.2继承关系和访问限定符 1.2.3继承基类成员访问方式的变化 总结&#xff1a; 2.基类和派生类对象赋值转换 3.继承中的作用域 4.派生类的默认成员函数 ​编辑 默认构造与传参构造 拷贝构造&am…...

NVMe(Non-Volatile Memory Express)详解

一、NVMe的定义与核心特性 NVMe&#xff08;非易失性内存主机控制器接口规范&#xff09;是一种 基于PCIe总线的高性能存储协议&#xff0c;专为固态硬盘&#xff08;SSD&#xff09;设计&#xff0c;旨在替代传统的AHCI协议&#xff08;如SATA&#xff09;。其核心特性包括&a…...

MySQL数据库精研之旅第二期:库操作的深度探索

专栏&#xff1a;MySQL数据库成长记 个人主页&#xff1a;手握风云 目录 一、查看数据库 二、创建数据库 2.1. 语法 2.2. 示例 三、字符集编码和校验(排序)规则 3.1. 查看数据库支持的字符集编码 3.2. 查看数据库支持的排序规则 3.3. 不同的字串集与排序规则对数据库的…...

git_version_control_proper_practice

git_version_control_proper_practice version control&#xff0c;版本控制的方法之一就是打tag 因为多人协作的项目团队&#xff0c;commit很多&#xff0c;所以需要给重要的commit打tag&#xff0c;方便checkout&#xff0c;检出这个tag 参考行业的实践方式。如图git、linux…...

从单任务到多任务:进程与线程如何实现并发?

文章目录 1. 什么是进程定义进程的构成进程的状态进程与线程的关系进程的创建与销毁进程调度进程间通信&#xff08;IPC&#xff09;总结 2. 什么是线程&#xff1f;定义线程与进程的关系线程的特点线程的优点线程的类型线程的创建与销毁线程间通信总结 3. 进程与线程有什么区别…...

计算机组成原理和计算机网络常见单位分类及换算

计算机组成原理&#xff08;主要用于存储、内存、缓存等&#xff09; 计算机网络&#xff08;主要用于传输速率&#xff09; 直观对比...

【第二十八周】:Temporal Segment Networks:用于视频动作识别的时间分段网络

TSN 摘要Abstract文章信息引言方法时间分段采样分段聚合输入模态聚合函数多尺度时序窗口集成&#xff08;M-TWI&#xff09;训练 代码实现实验结果总结 摘要 本篇博客介绍了时间分段网络&#xff08;Temporal Segment Network, TSN&#xff09;&#xff0c;这是一种针对视频动…...